mirror of
https://codeberg.org/ProgramSnail/lang.git
synced 2025-12-05 22:48:43 +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 Names = names::NameTree;
|
||||
using Positions = core::DependentStorage<utils::Pos>;
|
||||
using NodeTypes =
|
||||
core::DependentStorage<nodes::Type>; // deduce type for each node
|
||||
using Printer = printers::Printer;
|
||||
|
||||
// TODO: partial host ?? (part of params are stored in each executor, use if
|
||||
// constexpr requires) (for Printer, State, ...)
|
||||
using ExecutorHost =
|
||||
core::ExecutorHost<Exprs, Types, Names, Positions,
|
||||
core::ExecutorHost<Exprs, Types, Names, Positions, NodeTypes,
|
||||
builders::State /*, type_check::State*/, Printer>;
|
||||
|
||||
class SourcesManager {
|
||||
public:
|
||||
SourcesManager(Log &&log, Printer &&printer)
|
||||
: executor_host_(std::move(log), {}, {}, {}, {}, {}, std::move(printer)),
|
||||
: executor_host_(std::move(log), {}, {}, {}, {}, {}, {},
|
||||
std::move(printer)),
|
||||
statements_{} {}
|
||||
|
||||
void AddFile(const std::string &filename) {
|
||||
|
|
|
|||
|
|
@ -55,8 +55,9 @@ template <typename N> struct BuilderTaskUtils : public Task<N> {
|
|||
return value;
|
||||
}
|
||||
|
||||
template <typename T> Node Build(T value, utils::Pos pos) {
|
||||
auto id = this->template state<Exprs>().Insert(std::move(value));
|
||||
template <typename T> Node Build(T value, bool is_scoped, utils::Pos pos) {
|
||||
auto id =
|
||||
this->template state<Exprs>().Insert({std::move(value), is_scoped});
|
||||
this->template state<Positions>().ForceInsert(id, pos);
|
||||
return Ext(id);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -96,7 +96,7 @@ struct BuilderTask<nodes::Container, T>
|
|||
// '{' (expression ';')* '}'
|
||||
// or
|
||||
// '[[' 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);
|
||||
|
||||
const auto kind = std::is_same_v<T, utils::BlockTag>
|
||||
|
|
@ -117,7 +117,7 @@ struct BuilderTask<nodes::Container, T>
|
|||
.kind = kind,
|
||||
.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
|
||||
// or
|
||||
// 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);
|
||||
|
||||
const size_t modifier_pos =
|
||||
|
|
@ -184,7 +184,7 @@ struct BuilderTask<nodes::ModifierExpression, T>
|
|||
RunOther<nodes::Modifier>(parser_node.nth_child(modifier_pos)),
|
||||
.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{
|
||||
.name = RunOther<nodes::Identifier>(parser_node),
|
||||
},
|
||||
parser_node.get_pos()); // TODO: is_scoped
|
||||
is_scoped, parser_node.get_pos());
|
||||
case tokens::Type::CONSTRUCTOR:
|
||||
return Run<nodes::Constructor>(parser_node);
|
||||
case tokens::Type::LAMBDA:
|
||||
return Run<nodes::Lambda>(parser_node);
|
||||
// --- literals
|
||||
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());
|
||||
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());
|
||||
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());
|
||||
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());
|
||||
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());
|
||||
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());
|
||||
case tokens::Type::UNICODE_STRING_LITERAL:
|
||||
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:
|
||||
return Build(RunOther<nodes::Literal, char>(parser_node),
|
||||
return Build(RunOther<nodes::Literal, char>(parser_node), is_scoped,
|
||||
parser_node.get_pos());
|
||||
case tokens::Type::UNICODE_LITERAL:
|
||||
return Build(RunOther<nodes::Literal, nodes::unicode>(parser_node),
|
||||
parser_node.get_pos());
|
||||
is_scoped, parser_node.get_pos());
|
||||
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());
|
||||
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());
|
||||
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());
|
||||
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:
|
||||
return Build(RunOther<nodes::EmptyLines>(parser_node),
|
||||
return Build(RunOther<nodes::EmptyLines>(parser_node), is_scoped,
|
||||
parser_node.get_pos());
|
||||
default:
|
||||
break;
|
||||
|
|
@ -152,7 +153,7 @@ Node BuilderTask<Node>::operator()(const ParserNode &parser_node,
|
|||
|
||||
// (':=' | '=:') expression (('??' | 'if') expression)? (_do_ expression)?
|
||||
Node BuilderTask<nodes::Match::Case>::operator()(const ParserNode &parser_node,
|
||||
const Args &) {
|
||||
const Args &args) {
|
||||
Log::Context logc(executor.log(), Log::Area::kParse);
|
||||
|
||||
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())
|
||||
: std::optional<nodes::NodeId>(),
|
||||
},
|
||||
parser_node.get_pos());
|
||||
args.is_scoped, parser_node.get_pos());
|
||||
}
|
||||
|
||||
// expression case+
|
||||
Node BuilderTask<nodes::Match>::operator()(const ParserNode &parser_node,
|
||||
const Args &) {
|
||||
const Args &args) {
|
||||
Log::Context logc(executor.log(), Log::Area::kParse);
|
||||
|
||||
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 ??)
|
||||
.cases = std::move(cases),
|
||||
},
|
||||
parser_node.get_pos());
|
||||
args.is_scoped, parser_node.get_pos());
|
||||
}
|
||||
|
||||
// ('??' | 'if') expression _do_ expression (('!!' | 'elif') expression _do_
|
||||
// expression)* (('!!=>', 'else') expression)?
|
||||
Node BuilderTask<nodes::Condition>::operator()(const ParserNode &parser_node,
|
||||
const Args &) {
|
||||
const Args &args) {
|
||||
Log::Context logc(executor.log(), Log::Area::kParse);
|
||||
|
||||
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))
|
||||
: std::optional<Node>(),
|
||||
},
|
||||
parser_node.get_pos());
|
||||
args.is_scoped, parser_node.get_pos());
|
||||
}
|
||||
|
||||
// ('@' | 'for') (expression | expression ':' expression)? _do_ expression
|
||||
Node BuilderTask<nodes::Loop>::operator()(const ParserNode &parser_node,
|
||||
const Args &) {
|
||||
const Args &args) {
|
||||
Log::Context logc(executor.log(), Log::Area::kParse);
|
||||
|
||||
size_t named_child_count = parser_node.named_child_count();
|
||||
|
||||
if (named_child_count == 1) { // body
|
||||
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,
|
||||
// body
|
||||
return Build(nodes::Loop(Run<Node>(parser_node.nth_named_child(0)),
|
||||
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,
|
||||
// interval,
|
||||
// body
|
||||
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(2))),
|
||||
parser_node.get_pos());
|
||||
args.is_scoped, parser_node.get_pos());
|
||||
} else {
|
||||
logc.Fatal<Log::kProc>({{"Unexpected named expression amount in loop"}},
|
||||
parser_node.get_pos());
|
||||
|
|
@ -281,16 +282,16 @@ Node BuilderTask<nodes::Loop>::operator()(const ParserNode &parser_node,
|
|||
|
||||
// expression ',' expression
|
||||
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);
|
||||
|
||||
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,
|
||||
Run<nodes::NodeId>(parser_node.nth_named_child(0)));
|
||||
args_nodes.emplace_back(std::nullopt,
|
||||
Run<nodes::NodeId>(parser_node.nth_named_child(0)));
|
||||
|
||||
args.emplace_back(std::nullopt,
|
||||
Run<nodes::NodeId>(parser_node.nth_named_child(1)));
|
||||
args_nodes.emplace_back(std::nullopt,
|
||||
Run<nodes::NodeId>(parser_node.nth_named_child(1)));
|
||||
|
||||
return Build(
|
||||
nodes::NameExpression{
|
||||
|
|
@ -300,37 +301,38 @@ Node BuilderTask<nodes::NameExpression, utils::CommaTag>::operator()(
|
|||
.kind = nodes::Identifier::kSimpleName,
|
||||
.value = ",",
|
||||
},
|
||||
.args = std::move(args),
|
||||
.args = std::move(args_nodes),
|
||||
.prefix = {},
|
||||
.is_point_call = false,
|
||||
.is_operator_call = true,
|
||||
},
|
||||
parser_node.get_pos());
|
||||
args.is_scoped, parser_node.get_pos());
|
||||
}
|
||||
|
||||
// expression operator expression
|
||||
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);
|
||||
|
||||
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,
|
||||
Run<Node>(name_node.previous_named_sibling()));
|
||||
args_nodes.emplace_back(std::nullopt,
|
||||
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(
|
||||
nodes::NameExpression{
|
||||
.name = RunOther<nodes::Identifier, utils::OperatorIdTag>(name_node),
|
||||
.args = std::move(args),
|
||||
.args = std::move(args_nodes),
|
||||
.prefix = {},
|
||||
.is_point_call = false,
|
||||
.is_operator_call = true,
|
||||
},
|
||||
parser_node.get_pos());
|
||||
args.is_scoped, parser_node.get_pos());
|
||||
}
|
||||
|
||||
// --- continers
|
||||
|
|
@ -341,7 +343,7 @@ Node BuilderTask<nodes::NameExpression, utils::OperatorTag>::operator()(
|
|||
|
||||
// ('return' | 'bring') expression
|
||||
Node BuilderTask<nodes::Return>::operator()(const ParserNode &parser_node,
|
||||
const Args &) {
|
||||
const Args &args) {
|
||||
Log::Context logc(executor.log(), Log::Area::kParse);
|
||||
|
||||
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,
|
||||
.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)
|
||||
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);
|
||||
|
||||
std::string modifier = parser_node.nth_child(0).get_value();
|
||||
|
|
@ -371,24 +373,24 @@ Node BuilderTask<nodes::NameDefinition>::operator()(
|
|||
: nodes::NameDefinition::VAR,
|
||||
.name = RunOther<nodes::Identifier>(name_node),
|
||||
},
|
||||
parser_node.get_pos());
|
||||
args.is_scoped, parser_node.get_pos());
|
||||
} // IN PROGRESS
|
||||
|
||||
// expression '[' expression ']'
|
||||
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);
|
||||
|
||||
return Build(
|
||||
nodes::Access{.kind = nodes::Access::ARRAY,
|
||||
.value = Run<Node>(parser_node.nth_named_child(0)),
|
||||
.index = Run<Node>(parser_node.nth_named_child(1))},
|
||||
parser_node.get_pos());
|
||||
args.is_scoped, parser_node.get_pos());
|
||||
}
|
||||
|
||||
// expression '.' number_literal
|
||||
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);
|
||||
|
||||
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(
|
||||
// 1)) /*, false}*/, // ?? is_scoped ??
|
||||
},
|
||||
parser_node.get_pos());
|
||||
args.is_scoped, parser_node.get_pos());
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
// 'break' | 'continue'
|
||||
Node BuilderTask<nodes::LoopControl>::operator()(const ParserNode &parser_node,
|
||||
const Args &) {
|
||||
const Args &args) {
|
||||
Log::Context logc(executor.log(), Log::Area::kParse);
|
||||
|
||||
return Build(
|
||||
|
|
@ -416,7 +418,7 @@ Node BuilderTask<nodes::LoopControl>::operator()(const ParserNode &parser_node,
|
|||
? nodes::LoopControl::BREAK
|
||||
: nodes::LoopControl::CONTINUE,
|
||||
},
|
||||
parser_node.get_pos());
|
||||
args.is_scoped, parser_node.get_pos());
|
||||
}
|
||||
|
||||
// // 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
|
||||
// ')') (annotation? expression)*
|
||||
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);
|
||||
|
||||
std::vector<nodes::AnnotatedArgument> args;
|
||||
std::vector<nodes::AnnotatedArgument> args_nodes;
|
||||
|
||||
std::optional<nodes::TypeData> prefix;
|
||||
|
||||
|
|
@ -474,60 +476,60 @@ Node BuilderTask<nodes::NameExpression, utils::FuncCallTag>::operator()(
|
|||
prefix_node = current_node;
|
||||
} else {
|
||||
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(
|
||||
nodes::NameExpression{
|
||||
.name = RunOther<nodes::Identifier>(name_node),
|
||||
.args = std::move(args),
|
||||
.args = std::move(args_nodes),
|
||||
.prefix = prefix_node.has_value()
|
||||
? RunOther<nodes::Type>(prefix_node.value())
|
||||
: nodes::MaybeType(),
|
||||
.is_point_call = is_point_call,
|
||||
.is_operator_call = false,
|
||||
},
|
||||
parser_node.get_pos());
|
||||
args.is_scoped, parser_node.get_pos());
|
||||
}
|
||||
|
||||
// type (annotation? expression)*
|
||||
Node BuilderTask<nodes::Constructor>::operator()(const ParserNode &parser_node,
|
||||
const Args &) {
|
||||
const Args &args) {
|
||||
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
|
||||
.child_by_field_name("ty"
|
||||
"p"
|
||||
"e")
|
||||
.next_named_sibling(),
|
||||
executor, args);
|
||||
executor, args_nodes);
|
||||
|
||||
return Build(
|
||||
nodes::Constructor{
|
||||
.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
|
||||
Node BuilderTask<nodes::Lambda>::operator()(const ParserNode &parser_node,
|
||||
const Args &) {
|
||||
const Args &args) {
|
||||
Log::Context logc(executor.log(), Log::Area::kParse);
|
||||
|
||||
std::vector<nodes::Identifier> args;
|
||||
std::vector<nodes::Identifier> args_nodes;
|
||||
|
||||
auto current_node =
|
||||
parser_node.nth_child(1); // next to '\\', not null ('=>' should present)
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
|
|
@ -536,10 +538,10 @@ Node BuilderTask<nodes::Lambda>::operator()(const ParserNode &parser_node,
|
|||
|
||||
return Build(
|
||||
nodes::Lambda{
|
||||
.args = std::move(args),
|
||||
.args = std::move(args_nodes),
|
||||
.expr = Run<Node>(current_node),
|
||||
},
|
||||
parser_node.get_pos());
|
||||
args.is_scoped, parser_node.get_pos());
|
||||
}
|
||||
|
||||
} // namespace builders
|
||||
|
|
|
|||
|
|
@ -25,8 +25,8 @@ public:
|
|||
public:
|
||||
State(Log &log) : log_(log) {}
|
||||
|
||||
bool insert_variable(const std::string &name, nodes::Type type,
|
||||
nodes::NameDefinition::Kind modifier) {
|
||||
bool InsertVariable(const std::string &name, nodes::Type type,
|
||||
nodes::NameDefinition::Kind modifier) {
|
||||
Log::Context logc(log_, Log::Area::kTypeCheck);
|
||||
|
||||
if (contexts_.empty()) {
|
||||
|
|
@ -39,7 +39,7 @@ public:
|
|||
.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) {
|
||||
auto iter = contexts_[i].variables.find(name);
|
||||
if (iter != contexts_[i].variables.end()) {
|
||||
|
|
@ -50,7 +50,7 @@ public:
|
|||
return std::nullopt;
|
||||
}
|
||||
|
||||
bool bring_type(nodes::Type type) {
|
||||
bool BringType(nodes::Type type) {
|
||||
Log::Context logc(log_, Log::Area::kTypeCheck);
|
||||
|
||||
if (contexts_.empty()) {
|
||||
|
|
@ -66,7 +66,7 @@ public:
|
|||
return true;
|
||||
}
|
||||
|
||||
bool return_type(nodes::Type type) {
|
||||
bool ReturnType(nodes::Type type) {
|
||||
Log::Context logc(log_, Log::Area::kTypeCheck);
|
||||
|
||||
if (contexts_.empty()) {
|
||||
|
|
@ -83,7 +83,7 @@ public:
|
|||
}
|
||||
|
||||
private:
|
||||
void enter_context(const utils::Pos &pos) {
|
||||
void EnterContext(const utils::Pos &pos) {
|
||||
Log::Context logc(log_, Log::Area::kTypeCheck);
|
||||
|
||||
contexts_.emplace_back(pos);
|
||||
|
|
@ -164,10 +164,14 @@ using Exprs = nodes::NodeStorage;
|
|||
using Types = nodes::TypeStorage;
|
||||
using Names = names::NameTree;
|
||||
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:
|
||||
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);
|
||||
copy.expected_types_ = {executor.state<Types>().primitive(type)};
|
||||
return copy;
|
||||
}
|
||||
|
||||
Args pass_builtin(builtin::Type type, Executor &executor) const {
|
||||
Args PassBuiltin(builtin::Type type, Executor &executor) const {
|
||||
Args copy(*this);
|
||||
copy.passed_type_ = executor.state<Types>().primitive(type);
|
||||
return copy;
|
||||
}
|
||||
|
||||
Args expect(nodes::Types types) const {
|
||||
Args Expect(nodes::Types types) const {
|
||||
Args copy(*this);
|
||||
copy.expected_types_ = types;
|
||||
return copy;
|
||||
}
|
||||
|
||||
Args expect(nodes::MaybeType type) const {
|
||||
Args Expect(nodes::MaybeType type) const {
|
||||
Args copy(*this);
|
||||
copy.expected_types_ =
|
||||
(type.has_value() ? nodes::Types{type.value()} : nodes::Types{});
|
||||
return copy;
|
||||
}
|
||||
|
||||
Args pass(nodes::MaybeType type) const {
|
||||
Args Pass(nodes::MaybeType type) const {
|
||||
Args copy(*this);
|
||||
copy.passed_type_ = type;
|
||||
return copy;
|
||||
}
|
||||
|
||||
Args without_expect() const {
|
||||
Args WithoutExpect() const {
|
||||
Args copy(*this);
|
||||
copy.expected_types_ = {};
|
||||
return copy;
|
||||
}
|
||||
|
||||
Args without_pass() const {
|
||||
Args WithoutPass() const {
|
||||
Args copy(*this);
|
||||
copy.passed_type_ = {};
|
||||
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: args builder ??
|
||||
|
|
@ -240,7 +244,7 @@ public:
|
|||
ContextHolder(State &state, const utils::Pos &pos,
|
||||
nodes::MaybeType *context_exit_type)
|
||||
: state_(state), context_exit_type_(context_exit_type) {
|
||||
state.enter_context(pos);
|
||||
state.EnterContext(pos);
|
||||
}
|
||||
|
||||
ContextHolder(const ContextHolder &) = delete;
|
||||
|
|
@ -273,14 +277,14 @@ public:
|
|||
|
||||
//
|
||||
|
||||
nodes::Type &get() {
|
||||
nodes::Type &Get() {
|
||||
utils::Assert(type_.has_value(),
|
||||
"Access to invalid type in TypeCheckResult");
|
||||
|
||||
return type_.value();
|
||||
}
|
||||
|
||||
const nodes::Type &get() const {
|
||||
const nodes::Type &Get() const {
|
||||
|
||||
utils::Assert(type_.has_value(),
|
||||
"Access to invalid type in TypeCheckResult");
|
||||
|
|
@ -288,7 +292,15 @@ public:
|
|||
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,
|
||||
Executor &executor,
|
||||
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,
|
||||
// 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,
|
||||
Executor &executor,
|
||||
const std::string &message = "Different type with expected one",
|
||||
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 *>
|
||||
find_type_definition(const std::string &name, const utils::Pos &pos,
|
||||
Executor &executor, bool handle_errors = true);
|
||||
FindTypeDefinition(const std::string &name, const utils::Pos &pos,
|
||||
Executor &executor, bool handle_errors = true);
|
||||
|
||||
std::optional<const nodes::FunctionDefinition *>
|
||||
find_name_definition(const std::string &name, const utils::Pos &pos,
|
||||
Executor &executor, bool handle_errors = true);
|
||||
FindNameDefinition(const std::string &name, const utils::Pos &pos,
|
||||
Executor &executor, bool handle_errors = true);
|
||||
|
||||
nodes::MaybeType unfold_user_defined_type(nodes::Type type,
|
||||
const utils::Pos &pos,
|
||||
Executor &executor,
|
||||
bool handle_errors = true);
|
||||
nodes::MaybeType UnfoldUserDefinedType(nodes::Type type, const utils::Pos &pos,
|
||||
Executor &executor,
|
||||
bool handle_errors = true);
|
||||
|
||||
nodes::MaybeType get_field_type_by_name(nodes::Type type,
|
||||
const std::string &field,
|
||||
const utils::Pos &pos,
|
||||
Executor &executor,
|
||||
bool handle_errors = true);
|
||||
nodes::MaybeType FieldTypeByName(nodes::Type type, const std::string &field,
|
||||
const utils::Pos &pos, Executor &executor,
|
||||
bool handle_errors = true);
|
||||
|
||||
void type_check_error(const std::string &message, const utils::Pos &pos,
|
||||
Executor &executor, bool handle_error = true);
|
||||
inline nodes::MaybeType Curry(MaybeResult result) {
|
||||
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) {
|
||||
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) {
|
||||
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
|
||||
|
|
|
|||
|
|
@ -4,6 +4,8 @@ namespace type_check {
|
|||
|
||||
nodes::Type get_literal_type(const nodes::Literal &literal,
|
||||
Executor &executor) {
|
||||
Log::Context logc(executor.log(), Log::Area::kTypeCheck);
|
||||
|
||||
switch (literal.value.index()) {
|
||||
case 0: // float
|
||||
return executor.state<Types>().primitive(builtin::Type::FLOAT);
|
||||
|
|
@ -39,9 +41,11 @@ nodes::Type get_literal_type(const nodes::Literal &literal,
|
|||
|
||||
Result CheckTask<nodes::Literal>::operator()(const nodes::Literal &literal,
|
||||
const Args &args) {
|
||||
Log::Context logc(executor.log(), Log::Area::kTypeCheck);
|
||||
|
||||
auto const type = get_literal_type(literal, this->executor);
|
||||
return type_same_to_expected(type, args, {},
|
||||
this->executor); // TODO: add pos ??
|
||||
return CheckTypeSameToExpected(type, args, {},
|
||||
this->executor); // TODO: add pos ??
|
||||
}
|
||||
|
||||
} // namespace type_check
|
||||
|
|
|
|||
|
|
@ -35,16 +35,19 @@ Result CheckTask<nodes::NodeData>::operator()(const nodes::NodeData &expr,
|
|||
|
||||
Result CheckTask<nodes::Match>::operator()(const nodes::Match &expr,
|
||||
const Args &args) {
|
||||
Log::Context logc(executor.log(), Log::Area::kTypeCheck);
|
||||
const auto current_pos = PosOf(args.current_id);
|
||||
|
||||
//
|
||||
|
||||
Result value_result = Run(expr.value, {expr.value});
|
||||
|
||||
// x :=/=: ...
|
||||
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_without_expression = false;
|
||||
|
|
@ -54,95 +57,101 @@ Result CheckTask<nodes::Match>::operator()(const nodes::Match &expr,
|
|||
Ext(current_case_id).get<nodes::Match::Case>();
|
||||
|
||||
// :=/=: x ...
|
||||
Run(current_case.value,
|
||||
Args{current_case.value}
|
||||
.expect_builtin(builtin::Type::BOOL, executor)
|
||||
.pass(value_result.is_invalid() ? nodes::MaybeType{}
|
||||
: expression_result.value().get()));
|
||||
// TODO: use type modifiers ??
|
||||
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,
|
||||
Args{current_case.value}
|
||||
.ExpectBuiltin(builtin::Type::BOOL, executor)
|
||||
.Pass(value_result.Get()));
|
||||
}
|
||||
break;
|
||||
case nodes::Match::Case::VALUE_PATTERN:
|
||||
Run(current_case.value, Args{current_case.value}
|
||||
.ExpectBuiltin(builtin::Type::BOOL, executor)
|
||||
.Pass(value_result.MaybeGet()));
|
||||
break;
|
||||
}
|
||||
|
||||
// ... ?? x ...
|
||||
if (current_case.condition.has_value()) {
|
||||
Run(current_case.condition.value(),
|
||||
Args{current_case.condition.value()}.expect_builtin(
|
||||
builtin::Type::BOOL, executor));
|
||||
const auto &cond = current_case.condition.value();
|
||||
Run(cond, Args{cond}.ExpectBuiltin(builtin::Type::BOOL, executor));
|
||||
}
|
||||
|
||||
// ... -> x
|
||||
if (current_case.expr.has_value()) {
|
||||
const auto &expr = current_case.expr.value();
|
||||
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()) {
|
||||
expression_result = std::move(case_result);
|
||||
Result case_result = Run(expr, Args{expr}.Expect(Curry(expr_result)));
|
||||
|
||||
if (not expr_result.has_value() and not case_result.is_invalid()) {
|
||||
expr_result = std::move(case_result);
|
||||
}
|
||||
} else {
|
||||
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) {
|
||||
type_check_error(
|
||||
TypeCheckError(
|
||||
"All cases should be with or without expression at the same time",
|
||||
current_pos, executor);
|
||||
expression_result = Result::invalid();
|
||||
current_pos);
|
||||
expr_result = Result::invalid();
|
||||
}
|
||||
|
||||
if (!expression_result.has_value()) {
|
||||
expression_result = Result{state<Types>().primitive(builtin::Type::UNIT)};
|
||||
if (not expr_result.has_value()) {
|
||||
expr_result = Result{state<Types>().primitive(builtin::Type::UNIT)};
|
||||
}
|
||||
|
||||
return type_check_from_args(
|
||||
state<Types>().add_array_of(expression_result.value().get()), args,
|
||||
current_pos, executor);
|
||||
return TypeCheckFromArgs(expr_result.value().Get(), args, current_pos);
|
||||
}
|
||||
|
||||
Result CheckTask<nodes::Condition>::operator()(const nodes::Condition &expr,
|
||||
const Args &args) {
|
||||
Log::Context logc(executor.log(), Log::Area::kTypeCheck);
|
||||
const auto current_pos = PosOf(args.current_id);
|
||||
|
||||
MaybeResult expression_result;
|
||||
//
|
||||
|
||||
MaybeResult expr_result;
|
||||
|
||||
for (const auto ¤t_case : expr.cases) {
|
||||
// condition
|
||||
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 =
|
||||
Run(current_case.second,
|
||||
Args{current_case.second}.expect(
|
||||
expression_result.has_value() ? expression_result.value().get()
|
||||
: nodes::MaybeType{}));
|
||||
Args{current_case.second}.Expect(Curry(expr_result)));
|
||||
|
||||
if (!expression_result.has_value() && !case_result.is_invalid()) {
|
||||
expression_result = std::move(case_result);
|
||||
if (not expr_result.has_value() and not case_result.is_invalid()) {
|
||||
expr_result = std::move(case_result);
|
||||
}
|
||||
}
|
||||
|
||||
if (expr.else_case.has_value()) {
|
||||
Run(expr.else_case.value(),
|
||||
Args{expr.else_case.value()}.expect(
|
||||
expression_result.has_value() ? expression_result.value().get()
|
||||
: nodes::MaybeType{}));
|
||||
Args{expr.else_case.value()}.Expect(Curry(expr_result)));
|
||||
}
|
||||
|
||||
if (!expression_result.has_value()) {
|
||||
type_check_error("There should be at least one case in if statement",
|
||||
current_pos, executor);
|
||||
expression_result = Result::invalid();
|
||||
if (!expr_result.has_value()) {
|
||||
TypeCheckError("There should be at least one case in if statement",
|
||||
current_pos);
|
||||
expr_result = Result::invalid();
|
||||
}
|
||||
|
||||
return type_check_from_args(
|
||||
state<Types>().add_array_of(expression_result.value().get()), args,
|
||||
current_pos, executor);
|
||||
return TypeCheckFromArgs(expr_result.value().Get(), args, current_pos);
|
||||
}
|
||||
|
||||
Result CheckTask<nodes::Loop>::operator()(const nodes::Loop &expr,
|
||||
const Args &args) {
|
||||
Log::Context logc(executor.log(), Log::Area::kTypeCheck);
|
||||
|
||||
const auto current_pos = PosOf(args.current_id);
|
||||
|
||||
// TODO: ranges ??
|
||||
|
|
@ -157,7 +166,7 @@ Result CheckTask<nodes::Loop>::operator()(const nodes::Loop &expr,
|
|||
case nodes::Loop::LOOP: // infinity loop, no params
|
||||
break;
|
||||
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));
|
||||
|
||||
// --- type check is independent from loop itself ---
|
||||
|
|
@ -169,7 +178,7 @@ Result CheckTask<nodes::Loop>::operator()(const nodes::Loop &expr,
|
|||
case nodes::Loop::FOR:
|
||||
// TODO: expect range ??
|
||||
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));
|
||||
|
||||
if (interval_result.value().is_invalid()) {
|
||||
|
|
@ -180,8 +189,8 @@ Result CheckTask<nodes::Loop>::operator()(const nodes::Loop &expr,
|
|||
|
||||
variable_result =
|
||||
Run(expr.variable.value(),
|
||||
Args{expr.variable.value()}.expect(
|
||||
interval_result.value().get().get()->get_parameter_proxy(0)));
|
||||
Args{expr.variable.value()}.Expect(
|
||||
interval_result.value().Get().get()->get_parameter_proxy(0)));
|
||||
|
||||
// --- type check is independent from loop itself ---
|
||||
// if (variable_result.value().is_invalid()) {
|
||||
|
|
@ -196,15 +205,16 @@ Result CheckTask<nodes::Loop>::operator()(const nodes::Loop &expr,
|
|||
|
||||
// TODO: modifier checks ??, modifiers ??
|
||||
|
||||
return type_check_from_args(
|
||||
state<Types>().add_array_of(expression_result.get()), args, current_pos,
|
||||
executor);
|
||||
return TypeCheckFromArgs(state<Types>().add_array_of(expression_result.Get()),
|
||||
args, current_pos);
|
||||
} // IN PROGRESS
|
||||
|
||||
// --- containers
|
||||
|
||||
Result CheckTask<nodes::Container>::CheckArray(const nodes::Container &expr,
|
||||
const Args &args) {
|
||||
Log::Context logc(executor.log(), Log::Area::kTypeCheck);
|
||||
|
||||
const auto current_pos = PosOf(args.current_id);
|
||||
|
||||
MaybeResult last_expr_result;
|
||||
|
|
@ -216,9 +226,9 @@ Result CheckTask<nodes::Container>::CheckArray(const nodes::Container &expr,
|
|||
if (!last_expr_result.has_value()) {
|
||||
last_expr_result = expr_result;
|
||||
} else {
|
||||
if (last_expr_result.value().get() != expr_result.get()) {
|
||||
type_check_error("Elements in array should have same type",
|
||||
PosOf(args.current_id), executor);
|
||||
if (last_expr_result.value().Get() != expr_result.Get()) {
|
||||
TypeCheckError("Elements in array should have same type",
|
||||
PosOf(args.current_id));
|
||||
// return TypeCheckResult::construct_invalid_result(); // max
|
||||
// possible checks, so no return
|
||||
}
|
||||
|
|
@ -226,17 +236,19 @@ Result CheckTask<nodes::Container>::CheckArray(const nodes::Container &expr,
|
|||
}
|
||||
|
||||
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 type_check_from_args(
|
||||
state<Types>().add_array_of(last_expr_result.value().get()), args,
|
||||
current_pos, executor);
|
||||
return TypeCheckFromArgs(
|
||||
state<Types>().add_array_of(last_expr_result.value().Get()), args,
|
||||
current_pos);
|
||||
}
|
||||
|
||||
Result CheckTask<nodes::Container>::CheckBlock(const nodes::Container &expr,
|
||||
const Args &args) {
|
||||
Log::Context logc(executor.log(), Log::Area::kTypeCheck);
|
||||
|
||||
const auto current_pos = PosOf(args.current_id);
|
||||
|
||||
nodes::MaybeType context_exit_type;
|
||||
|
|
@ -257,9 +269,8 @@ Result CheckTask<nodes::Container>::CheckBlock(const nodes::Container &expr,
|
|||
? Result(context_exit_type.value())
|
||||
: Result(state<Types>().primitive(builtin::Type::UNIT));
|
||||
|
||||
return type_check_from_args(
|
||||
state<Types>().add_array_of(block_brought_type.get()), args, current_pos,
|
||||
executor);
|
||||
return TypeCheckFromArgs(
|
||||
state<Types>().add_array_of(block_brought_type.Get()), args, current_pos);
|
||||
}
|
||||
|
||||
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,
|
||||
const Args &args) {
|
||||
Log::Context logc(executor.log(), Log::Area::kTypeCheck);
|
||||
|
||||
const auto current_pos = PosOf(args.current_id);
|
||||
|
||||
auto returned_result = Run(expr.expr, {expr.expr});
|
||||
|
|
@ -286,70 +299,71 @@ Result CheckTask<nodes::Return>::operator()(const nodes::Return &expr,
|
|||
|
||||
switch (expr.kind) {
|
||||
case nodes::Return::BRING:
|
||||
if (state<State>().bring_type(returned_result.get())) {
|
||||
type_check_error("Different brought type to current one", current_pos,
|
||||
executor);
|
||||
if (state<State>().BringType(returned_result.Get())) {
|
||||
TypeCheckError("Different brought type to current one", current_pos);
|
||||
return Result::invalid();
|
||||
}
|
||||
break;
|
||||
case nodes::Return::RETURN:
|
||||
if (!state<State>().return_type(returned_result.get())) {
|
||||
type_check_error("Different returned type to current one", current_pos,
|
||||
executor);
|
||||
if (!state<State>().ReturnType(returned_result.Get())) {
|
||||
TypeCheckError("Different returned type to current one", current_pos);
|
||||
return Result::invalid();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return type_check_from_args(state<Types>().primitive(builtin::Type::UNIT),
|
||||
args, current_pos, executor);
|
||||
return TypeCheckFromArgs(state<Types>().primitive(builtin::Type::UNIT), args,
|
||||
current_pos);
|
||||
}
|
||||
|
||||
// TODO: warning if name is same to package prefix, function prefix, etc. ??
|
||||
Result
|
||||
CheckTask<nodes::NameDefinition>::operator()(const nodes::NameDefinition &expr,
|
||||
const Args &args) {
|
||||
Log::Context logc(executor.log(), Log::Area::kTypeCheck);
|
||||
|
||||
const auto current_pos = PosOf(args.current_id);
|
||||
|
||||
if (!args.get_passed().has_value()) {
|
||||
type_check_error("Can't deduce type of new variable from context",
|
||||
current_pos, executor);
|
||||
if (!args.passed().has_value()) {
|
||||
TypeCheckError("Can't deduce type of new variable from context",
|
||||
current_pos);
|
||||
}
|
||||
|
||||
// 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(
|
||||
variable_type.get()
|
||||
->get_modifier())) { // TODO: utils::modifier_contains_OUT
|
||||
type_check_error("Variable can't be assigned from out (->) value",
|
||||
current_pos, executor);
|
||||
TypeCheckError("Variable can't be assigned from out (->) value",
|
||||
current_pos);
|
||||
}
|
||||
|
||||
// variable accessible by reference by default ??
|
||||
state<Types>().add_modification_of(variable_type, nodes::Modifier::REF);
|
||||
|
||||
if (!state<State>().insert_variable(expr.name.value, variable_type,
|
||||
expr.kind)) {
|
||||
type_check_error("Variable is already defined in this context", current_pos,
|
||||
executor);
|
||||
if (!state<State>().InsertVariable(expr.name.value, variable_type,
|
||||
expr.kind)) {
|
||||
TypeCheckError("Variable is already defined in this context", current_pos);
|
||||
}
|
||||
|
||||
// Return BOOL as any := / =: expression
|
||||
return type_check_from_args(state<Types>().primitive(builtin::Type::BOOL),
|
||||
args, current_pos, executor);
|
||||
return TypeCheckFromArgs(state<Types>().primitive(builtin::Type::BOOL), args,
|
||||
current_pos);
|
||||
}
|
||||
|
||||
Result CheckTask<nodes::Access>::CheckArrayAccess(const nodes::Access &expr,
|
||||
const Args &args) {
|
||||
Log::Context logc(executor.log(), Log::Area::kTypeCheck);
|
||||
|
||||
const auto current_pos = PosOf(args.current_id);
|
||||
|
||||
auto index_result =
|
||||
Run(expr.index,
|
||||
Args{expr.index}.expect_builtin(builtin::Type::INDEX, executor));
|
||||
Args{expr.index}.ExpectBuiltin(builtin::Type::INDEX, executor));
|
||||
|
||||
auto value_result =
|
||||
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()) {
|
||||
return index_result;
|
||||
|
|
@ -361,17 +375,19 @@ Result CheckTask<nodes::Access>::CheckArrayAccess(const nodes::Access &expr,
|
|||
|
||||
// TODO: modifier checks ??
|
||||
|
||||
return type_check_from_args(value_result.get().get()->get_parameter_proxy(0),
|
||||
args, current_pos, executor);
|
||||
return TypeCheckFromArgs(value_result.Get().get()->get_parameter_proxy(0),
|
||||
args, current_pos);
|
||||
}
|
||||
|
||||
Result CheckTask<nodes::Access>::CheckTupleAccess(const nodes::Access &expr,
|
||||
const Args &args) {
|
||||
Log::Context logc(executor.log(), Log::Area::kTypeCheck);
|
||||
|
||||
const auto current_pos = PosOf(args.current_id);
|
||||
|
||||
auto value_result =
|
||||
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()) {
|
||||
return value_result;
|
||||
|
|
@ -384,13 +400,14 @@ Result CheckTask<nodes::Access>::CheckTupleAccess(const nodes::Access &expr,
|
|||
|
||||
// TODO: modifier checks ??
|
||||
|
||||
return type_check_from_args(
|
||||
value_result.get().get()->get_parameter_proxy(index), args, current_pos,
|
||||
executor);
|
||||
return TypeCheckFromArgs(value_result.Get().get()->get_parameter_proxy(index),
|
||||
args, current_pos);
|
||||
}
|
||||
|
||||
Result CheckTask<nodes::Access>::operator()(const nodes::Access &expr,
|
||||
const Args &args) {
|
||||
Log::Context logc(executor.log(), Log::Area::kTypeCheck);
|
||||
|
||||
switch (expr.kind) {
|
||||
case nodes::Access::ARRAY:
|
||||
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,
|
||||
const Args &args) {
|
||||
Log::Context logc(executor.log(), Log::Area::kTypeCheck);
|
||||
|
||||
const auto current_pos = PosOf(args.current_id);
|
||||
|
||||
return type_check_from_args(state<Types>().primitive(builtin::Type::UNIT),
|
||||
args, current_pos, executor);
|
||||
return TypeCheckFromArgs(state<Types>().primitive(builtin::Type::UNIT), args,
|
||||
current_pos);
|
||||
}
|
||||
|
||||
Result CheckTask<nodes::ModifierExpression>::operator()(
|
||||
const nodes::ModifierExpression &expr, const Args &args) {
|
||||
Log::Context logc(executor.log(), Log::Area::kTypeCheck);
|
||||
|
||||
const auto current_pos = PosOf(args.current_id);
|
||||
|
||||
auto modified_result = Run(expr.expr, {expr.expr});
|
||||
|
|
@ -426,25 +447,23 @@ Result CheckTask<nodes::ModifierExpression>::operator()(
|
|||
|
||||
// '!' - 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::RESULT:
|
||||
// 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;
|
||||
default:
|
||||
type_check_error("Can unwrap only Optional or Result", current_pos,
|
||||
executor);
|
||||
TypeCheckError("Can unwrap only Optional or Result", current_pos);
|
||||
return Result::invalid();
|
||||
}
|
||||
} else {
|
||||
// TODO: check that modifier can be applied
|
||||
modified_result.set(state<Types>().add_modification_of(
|
||||
modified_result.get(), expr.modifier));
|
||||
modified_result.Set(state<Types>().add_modification_of(
|
||||
modified_result.Get(), expr.modifier));
|
||||
}
|
||||
|
||||
return type_check_from_args(modified_result.get(), args, current_pos,
|
||||
executor);
|
||||
return TypeCheckFromArgs(modified_result.Get(), args, current_pos);
|
||||
} // IN PROGRESS
|
||||
|
||||
// --- other
|
||||
|
|
@ -453,6 +472,8 @@ Result CheckTask<nodes::ModifierExpression>::operator()(
|
|||
Result
|
||||
CheckTask<nodes::NameExpression>::operator()(const nodes::NameExpression &expr,
|
||||
const Args &args) {
|
||||
Log::Context logc(executor.log(), Log::Area::kTypeCheck);
|
||||
|
||||
const auto current_pos = PosOf(args.current_id);
|
||||
|
||||
// TODO: constraints ??
|
||||
|
|
@ -470,7 +491,7 @@ CheckTask<nodes::NameExpression>::operator()(const nodes::NameExpression &expr,
|
|||
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()) {
|
||||
break;
|
||||
|
|
@ -494,8 +515,8 @@ CheckTask<nodes::NameExpression>::operator()(const nodes::NameExpression &expr,
|
|||
// TODO: switch by type types: Variant, Tuple, ...
|
||||
// Tuple -> try to find field
|
||||
// Others -> try to open / builtin fields ?
|
||||
const auto maybe_field_type = get_field_type_by_name(
|
||||
type, fragments[i].value, current_pos, executor);
|
||||
const auto maybe_field_type =
|
||||
FieldTypeByName(type, fragments[i].value, current_pos, executor);
|
||||
|
||||
if (maybe_field_type.has_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 var + fields
|
||||
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()) {
|
||||
return Result::invalid();
|
||||
}
|
||||
|
|
@ -531,15 +552,13 @@ CheckTask<nodes::NameExpression>::operator()(const nodes::NameExpression &expr,
|
|||
const auto args_defined = function_definition->args.size();
|
||||
if (args_given + 1 < args_defined ||
|
||||
args_given > args_defined) { // other, when there is passed type
|
||||
type_check_error(
|
||||
"Number of function args is different from expected (" +
|
||||
std::to_string(args_given) + " instead of " +
|
||||
std::to_string(args_defined) +
|
||||
std::string{args_defined > 0
|
||||
? (" or " + std::to_string(args_defined - 1))
|
||||
: ""} +
|
||||
")",
|
||||
current_pos, executor);
|
||||
TypeCheckError(std::format("Number of function args is different from "
|
||||
"expected ({} instead of {}{})",
|
||||
args_given, args_defined,
|
||||
args_defined > 0
|
||||
? (" or " + std::to_string(args_defined - 1))
|
||||
: ""),
|
||||
current_pos);
|
||||
return Result::invalid();
|
||||
// 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);
|
||||
|
||||
if (!argument.type.has_value()) {
|
||||
type_check_error("Function argument type is not defined for argument " +
|
||||
std::to_string(i),
|
||||
current_pos, executor);
|
||||
TypeCheckError(
|
||||
std::format("Function argument type is not defined for argument {}",
|
||||
i),
|
||||
current_pos);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
@ -563,30 +583,31 @@ CheckTask<nodes::NameExpression>::operator()(const nodes::NameExpression &expr,
|
|||
const auto expected_annotation = argument.annotation;
|
||||
|
||||
if (annotation.has_value() != expected_annotation.has_value()) {
|
||||
type_check_error("Wrong function argument annotation: should be " +
|
||||
std::string{expected_annotation.has_value()
|
||||
? expected_annotation.value()
|
||||
: "[none]"},
|
||||
PosOf(expr.args.at(i).second), executor);
|
||||
TypeCheckError("Wrong function argument annotation: should be " +
|
||||
std::string{expected_annotation.has_value()
|
||||
? expected_annotation.value()
|
||||
: "[none]"},
|
||||
PosOf(expr.args.at(i).second));
|
||||
}
|
||||
|
||||
if (annotation.has_value() &&
|
||||
annotation.value() != expected_annotation.value()) {
|
||||
type_check_error(
|
||||
"Wrong function argument type annotation: " + annotation.value() +
|
||||
" instead of " + expected_annotation.value(),
|
||||
PosOf(expr.args.at(i).second), executor);
|
||||
TypeCheckError(
|
||||
std::format(
|
||||
"Wrong function argument type annotation: {} instead of {}",
|
||||
annotation.value(), expected_annotation.value()),
|
||||
PosOf(expr.args.at(i).second));
|
||||
}
|
||||
|
||||
function_argument_results.push_back(
|
||||
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) {
|
||||
type_check_error(
|
||||
TypeCheckError(
|
||||
"Function arguments size is zero. Returned type is not defined",
|
||||
current_pos, executor);
|
||||
current_pos);
|
||||
return Result::invalid();
|
||||
}
|
||||
|
||||
|
|
@ -598,16 +619,14 @@ CheckTask<nodes::NameExpression>::operator()(const nodes::NameExpression &expr,
|
|||
|
||||
// TODO: invert modifier ??
|
||||
if (!returned.type.has_value()) {
|
||||
type_check_error(
|
||||
"Function argument type is not defined for returned type",
|
||||
current_pos, executor);
|
||||
TypeCheckError("Function argument type is not defined for returned type",
|
||||
current_pos);
|
||||
return Result::invalid();
|
||||
}
|
||||
|
||||
// TODO: invert modifier ??
|
||||
// TODO: generic types should be deduced from args
|
||||
return type_check_from_args(returned.type.value(), args, current_pos,
|
||||
executor);
|
||||
return TypeCheckFromArgs(returned.type.value(), args, current_pos);
|
||||
}
|
||||
|
||||
// checks for universal call syntax ??
|
||||
|
|
@ -618,12 +637,14 @@ CheckTask<nodes::NameExpression>::operator()(const nodes::NameExpression &expr,
|
|||
// TODO
|
||||
Result CheckTask<nodes::Constructor>::operator()(const nodes::Constructor &expr,
|
||||
const Args &args) {
|
||||
Log::Context logc(executor.log(), Log::Area::kTypeCheck);
|
||||
|
||||
const auto current_pos = PosOf(args.current_id);
|
||||
|
||||
// TODO: constraints ??
|
||||
|
||||
// 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);
|
||||
if (!maybe_type_definition.has_value()) {
|
||||
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();
|
||||
|
||||
if (!type_definition->type.has_value()) {
|
||||
type_check_error(
|
||||
TypeCheckError(
|
||||
"Type defenition for constructor type not found (declaration only)",
|
||||
current_pos, executor);
|
||||
current_pos);
|
||||
return Result::invalid();
|
||||
}
|
||||
|
||||
|
|
@ -646,8 +667,8 @@ Result CheckTask<nodes::Constructor>::operator()(const nodes::Constructor &expr,
|
|||
// TODO: work with different parametric types: tuple, variant, ...
|
||||
|
||||
if (expr.args.size() == 0) {
|
||||
type_check_error("Number of type constructor arguments should be > 0",
|
||||
current_pos, executor);
|
||||
TypeCheckError("Number of type constructor arguments should be > 0",
|
||||
current_pos);
|
||||
return Result::invalid();
|
||||
// TODO: try return correct type (constructor's type), when possible (not
|
||||
// generic)
|
||||
|
|
@ -661,12 +682,12 @@ Result CheckTask<nodes::Constructor>::operator()(const nodes::Constructor &expr,
|
|||
switch (builtin_type) {
|
||||
case builtin::Type::TUPLE:
|
||||
if (expr.args.size() != type.get()->parameters_size()) {
|
||||
type_check_error(
|
||||
TypeCheckError(
|
||||
"Number of type constructor arguments is different from expected "
|
||||
"(" +
|
||||
std::to_string(expr.args.size()) + " instead of " +
|
||||
std::to_string(type.get()->parameters_size()) + ")",
|
||||
current_pos, executor);
|
||||
current_pos);
|
||||
return Result::invalid();
|
||||
// TODO: try return correct type (constructor's type), when possible
|
||||
// (not generic)
|
||||
|
|
@ -679,10 +700,10 @@ Result CheckTask<nodes::Constructor>::operator()(const nodes::Constructor &expr,
|
|||
case builtin::Type::FUNCTION:
|
||||
case builtin::Type::NONE:
|
||||
if (expr.args.size() != 1) { // TODO: better to_string
|
||||
type_check_error("Number of type constructor arguments should be = 1 "
|
||||
"(builtin type " +
|
||||
std::to_string(uint(builtin_type)) + ")",
|
||||
current_pos, executor);
|
||||
TypeCheckError(std::format("Number of type constructor arguments "
|
||||
"should be = 1 (builtin type {})",
|
||||
uint(builtin_type)),
|
||||
current_pos);
|
||||
return Result::invalid();
|
||||
// TODO: try return correct type (constructor's type), when possible
|
||||
// (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() &&
|
||||
type.get()->parameters_size() !=
|
||||
builtin::types::get_parameters_count(builtin_type).value()) {
|
||||
type_check_error("Wrong amount of parametars for builtin type",
|
||||
current_pos, executor);
|
||||
TypeCheckError("Wrong amount of parametars for builtin type",
|
||||
current_pos);
|
||||
|
||||
return Result::invalid();
|
||||
// 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 (log_errors) {
|
||||
type_check_error(
|
||||
TypeCheckError(
|
||||
"Wrong type constructor argument annotation: should be " +
|
||||
std::string{expected_annotation.has_value()
|
||||
? *expected_annotation.value()
|
||||
: "[none]"},
|
||||
PosOf(expr.args.at(i).second), executor);
|
||||
PosOf(expr.args.at(i).second));
|
||||
}
|
||||
is_same = false;
|
||||
}
|
||||
|
|
@ -730,10 +751,10 @@ Result CheckTask<nodes::Constructor>::operator()(const nodes::Constructor &expr,
|
|||
if (annotation.has_value() &&
|
||||
annotation.value() != *expected_annotation.value()) {
|
||||
if (log_errors) {
|
||||
type_check_error("Wrong function argument type annotation: " +
|
||||
annotation.value() + " instead of " +
|
||||
*expected_annotation.value(),
|
||||
PosOf(expr.args.at(i).second), executor);
|
||||
TypeCheckError("Wrong function argument type annotation: " +
|
||||
annotation.value() + " instead of " +
|
||||
*expected_annotation.value(),
|
||||
PosOf(expr.args.at(i).second));
|
||||
}
|
||||
|
||||
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) {
|
||||
if (expr.args.at(i).first.has_value()) {
|
||||
if (log_errors) {
|
||||
type_check_error(
|
||||
TypeCheckError(
|
||||
"Type constructor argument annotation not expected there",
|
||||
PosOf(expr.args.at(i).second), executor);
|
||||
PosOf(expr.args.at(i).second));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
@ -774,9 +795,9 @@ Result CheckTask<nodes::Constructor>::operator()(const nodes::Constructor &expr,
|
|||
|
||||
if (!chosen_variant_option.has_value() &&
|
||||
!check_no_annotation(0, false /*do not log errors*/)) {
|
||||
type_check_error("Wrong type constructor argument annotation in "
|
||||
"constructor of variant type",
|
||||
PosOf(expr.args.front().second), executor);
|
||||
TypeCheckError("Wrong type constructor argument annotation in "
|
||||
"constructor of variant type",
|
||||
PosOf(expr.args.front().second));
|
||||
}
|
||||
break;
|
||||
case builtin::Type::ERROR: // no anotations ??
|
||||
|
|
@ -798,13 +819,13 @@ Result CheckTask<nodes::Constructor>::operator()(const nodes::Constructor &expr,
|
|||
switch (builtin_type) {
|
||||
case builtin::Type::TUPLE:
|
||||
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)));
|
||||
}
|
||||
break;
|
||||
case builtin::Type::VARIANT:
|
||||
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(
|
||||
chosen_variant_option.value())));
|
||||
} 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));
|
||||
}
|
||||
Run(expr.args.front().second,
|
||||
Args{expr.args.front().second}.expect(possible_options));
|
||||
Args{expr.args.front().second}.Expect(possible_options));
|
||||
}
|
||||
break;
|
||||
case builtin::Type::OPTIONAL:
|
||||
// first parameter or NULL
|
||||
Run(expr.args.front().second,
|
||||
Args{expr.args.front().second}.expect(
|
||||
Args{expr.args.front().second}.Expect(
|
||||
{type.get()->get_parameter_proxy(0),
|
||||
state<Types>().primitive(builtin::Type::NULL_OPTION)}));
|
||||
break;
|
||||
case builtin::Type::RESULT:
|
||||
// first parameter or ERROR[second parameter]
|
||||
Run(expr.args.front().second,
|
||||
Args{expr.args.front().second}.expect(
|
||||
Args{expr.args.front().second}.Expect(
|
||||
{type.get()->get_parameter_proxy(0),
|
||||
state<Types>().add_error_of(
|
||||
type.get()->get_parameter_proxy(1))}));
|
||||
break;
|
||||
case builtin::Type::ERROR:
|
||||
// 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)));
|
||||
break;
|
||||
case builtin::Type::FUNCTION:
|
||||
case builtin::Type::NONE:
|
||||
// type itself
|
||||
Run(expr.args.front().second,
|
||||
Args{expr.args.front().second}.expect(type));
|
||||
Args{expr.args.front().second}.Expect(type));
|
||||
break;
|
||||
default: // array, basic types
|
||||
type_check_error("Type can't be constructed", current_pos, executor);
|
||||
TypeCheckError("Type can't be constructed", current_pos);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// 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 ??
|
||||
|
||||
} // IN PROGRESS
|
||||
|
|
@ -858,71 +879,74 @@ Result CheckTask<nodes::Constructor>::operator()(const nodes::Constructor &expr,
|
|||
// TODO
|
||||
Result CheckTask<nodes::Lambda>::operator()(const nodes::Lambda &expr,
|
||||
const Args &args) {
|
||||
Log::Context logc(executor.log(), Log::Area::kTypeCheck);
|
||||
|
||||
const auto current_pos = PosOf(args.current_id);
|
||||
|
||||
if (args.get_expected().empty()) {
|
||||
type_check_error("Can't deduce type of lambda function from context: no "
|
||||
"one type expected",
|
||||
current_pos, executor);
|
||||
if (args.expected().empty()) {
|
||||
TypeCheckError("Can't deduce type of lambda function from context: no "
|
||||
"one type expected",
|
||||
current_pos);
|
||||
}
|
||||
|
||||
if (args.get_expected().size() !=
|
||||
if (args.expected().size() !=
|
||||
1) { // TODO: check if only one function argument
|
||||
type_check_error("Can't deduce type of lambda function from context; too "
|
||||
"much possible types",
|
||||
current_pos, executor);
|
||||
TypeCheckError("Can't deduce type of lambda function from context; too "
|
||||
"much possible types",
|
||||
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)) {
|
||||
type_check_error("Type of lambda function should be function", current_pos,
|
||||
executor);
|
||||
TypeCheckError("Type of lambda function should be function", current_pos);
|
||||
}
|
||||
|
||||
// TODO: deal with return type (+1 sometimes), etc
|
||||
const auto args_given = expr.args.size();
|
||||
const auto args_defined = expected_type.get()->parameters_size();
|
||||
if (args_given != args_defined) {
|
||||
type_check_error(
|
||||
"Number of function arguments is different from expected (" +
|
||||
std::to_string(args_given) + " instead of " +
|
||||
std::to_string(args_defined) +
|
||||
std::string{args_defined > 0
|
||||
? (" or " + std::to_string(args_defined - 1))
|
||||
: ""} +
|
||||
")",
|
||||
current_pos, executor);
|
||||
TypeCheckError(std::format("Number of function arguments is different from "
|
||||
"expected ({} istead of {}{})",
|
||||
args_given, args_defined,
|
||||
args_defined > 0
|
||||
? (" or " + std::to_string(args_defined - 1))
|
||||
: ""),
|
||||
current_pos);
|
||||
}
|
||||
|
||||
// TODO: set another context (for expression typecheck and vars)
|
||||
|
||||
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),
|
||||
nodes::NameDefinition::Kind::LET)) {
|
||||
// TODO: which modifier ??
|
||||
type_check_error("Variable is already defined in this context",
|
||||
current_pos, executor);
|
||||
TypeCheckError("Variable is already defined in this context",
|
||||
current_pos);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: out type is can be not last
|
||||
if (args_given + 1 == args_defined) {
|
||||
Run(expr.expr,
|
||||
Args{expr.expr}.expect(
|
||||
Args{expr.expr}.Expect(
|
||||
expected_type.get()->get_parameter_proxy(args_defined - 1)));
|
||||
}
|
||||
|
||||
// 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
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
Result CheckTask<nodes::EmptyLines>::operator()(const nodes::EmptyLines &,
|
||||
const Args &) {
|
||||
Log::Context logc(executor.log(), Log::Area::kTypeCheck);
|
||||
|
||||
return Result(state<Types>().primitive(builtin::Type::UNIT));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -6,43 +6,29 @@ namespace type_check {
|
|||
|
||||
// pass type -> compare types, return bool
|
||||
// no pass type -> return type
|
||||
nodes::Type check_same_to_pass_type_in_args(nodes::Type type, const Args &args,
|
||||
const utils::Pos &,
|
||||
Executor &executor,
|
||||
const std::string &message,
|
||||
bool handle_errors) {
|
||||
nodes::Type CheckSameToPassTypeInArgs(nodes::Type type, const Args &args,
|
||||
const utils::Pos &, Executor &executor,
|
||||
const std::string &message,
|
||||
bool handle_errors) {
|
||||
Log::Context logc(executor.log(), Log::Area::kTypeCheck);
|
||||
|
||||
if (not args.get_passed().has_value()) {
|
||||
if (not args.passed().has_value()) {
|
||||
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 */);
|
||||
}
|
||||
|
||||
return executor.state<Types>().primitive(builtin::Type::BOOL);
|
||||
}
|
||||
|
||||
bool check_no_pass_type_in_args(const Args &args, const utils::Pos &pos,
|
||||
Executor &executor, const std::string &message,
|
||||
bool handle_errors) {
|
||||
Result CheckTypeSameToExpected(nodes::Type type, const Args &args,
|
||||
const utils::Pos &, Executor &executor,
|
||||
const std::string &message, bool handle_errors) {
|
||||
Log::Context logc(executor.log(), Log::Area::kTypeCheck);
|
||||
|
||||
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 std::string &message, bool handle_errors) {
|
||||
Log::Context logc(executor.log(), Log::Area::kTypeCheck);
|
||||
|
||||
const auto &expected = args.get_expected();
|
||||
const auto &expected = args.expected();
|
||||
|
||||
if (expected.empty()) {
|
||||
return Result{type};
|
||||
|
|
@ -60,22 +46,12 @@ Result type_same_to_expected(nodes::Type type, const Args &args,
|
|||
return Result{expected.front()}; // any can be choosen
|
||||
}
|
||||
|
||||
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>
|
||||
std::optional<const T *>
|
||||
find_statement(const std::string &name, const utils::Pos &, Executor &executor,
|
||||
const std::string &message_not_found,
|
||||
const std::string &message_different_statement,
|
||||
bool handle_errors) {
|
||||
FindStatement(const std::string &name, const utils::Pos &, Executor &executor,
|
||||
const std::string &message_not_found,
|
||||
const std::string &message_different_statement,
|
||||
bool handle_errors) {
|
||||
Log::Context logc(executor.log(), Log::Area::kTypeCheck);
|
||||
|
||||
const auto maybe_any_statement = executor.state<names::NameTree>().find(name);
|
||||
|
|
@ -98,32 +74,32 @@ find_statement(const std::string &name, const utils::Pos &, Executor &executor,
|
|||
}
|
||||
|
||||
std::optional<const nodes::TypeDefinition *>
|
||||
find_type_definition(const std::string &name, const utils::Pos &pos,
|
||||
Executor &executor, bool handle_errors) {
|
||||
FindTypeDefinition(const std::string &name, const utils::Pos &pos,
|
||||
Executor &executor, bool handle_errors) {
|
||||
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",
|
||||
"Node in name tree is not type definition", handle_errors);
|
||||
}
|
||||
|
||||
std::optional<const nodes::FunctionDefinition *>
|
||||
find_name_definition(const std::string &name, const utils::Pos &pos,
|
||||
Executor &executor, bool handle_errors) {
|
||||
FindNameDefinition(const std::string &name, const utils::Pos &pos,
|
||||
Executor &executor, bool handle_errors) {
|
||||
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",
|
||||
"Node in name tree is not name definition", handle_errors);
|
||||
}
|
||||
|
||||
std::optional<nodes::Type> unfold_user_defined_type(nodes::Type type,
|
||||
const utils::Pos &pos,
|
||||
Executor &executor,
|
||||
bool handle_errors) {
|
||||
std::optional<nodes::Type> UnfoldUserDefinedType(nodes::Type type,
|
||||
const utils::Pos &pos,
|
||||
Executor &executor,
|
||||
bool handle_errors) {
|
||||
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);
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
std::optional<nodes::Type> get_field_type_by_name(nodes::Type type,
|
||||
const std::string &field,
|
||||
const utils::Pos &pos,
|
||||
Executor &executor,
|
||||
bool handle_errors) {
|
||||
std::optional<nodes::Type>
|
||||
FieldTypeByName(nodes::Type type, const std::string &field,
|
||||
const utils::Pos &pos, Executor &executor, bool handle_errors) {
|
||||
Log::Context logc(executor.log(), Log::Area::kTypeCheck);
|
||||
|
||||
switch (type.get()->to_builtin()) {
|
||||
|
|
@ -170,13 +144,13 @@ std::optional<nodes::Type> get_field_type_by_name(nodes::Type type,
|
|||
|
||||
// remove recursion ??
|
||||
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()) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
return get_field_type_by_name(maybe_internal_type.value(), field, pos,
|
||||
executor, handle_errors);
|
||||
return FieldTypeByName(maybe_internal_type.value(), field, pos, executor,
|
||||
handle_errors);
|
||||
}
|
||||
default: // variant, function, optional, result, error (TODO: add message
|
||||
// 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
|
||||
|
|
|
|||
|
|
@ -3,6 +3,8 @@
|
|||
#include "core_utils.hpp"
|
||||
#include "log.hpp"
|
||||
|
||||
// TODO: use Counter for Tasks
|
||||
|
||||
namespace core {
|
||||
|
||||
template <typename Tag>
|
||||
|
|
|
|||
|
|
@ -7,8 +7,9 @@
|
|||
namespace utils {
|
||||
|
||||
std::string to_string(const std::source_location &source_location) {
|
||||
return std::format("{}:{} {}", source_location.file_name(),
|
||||
source_location.line(), source_location.function_name());
|
||||
return std::format(
|
||||
"{}:{}" /* {}"*/, source_location.file_name(),
|
||||
source_location.line() /*, source_location.function_name()*/);
|
||||
}
|
||||
|
||||
std::string to_string(Pos::Point point) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue