typecheck refactoring start

This commit is contained in:
ProgramSnail 2024-09-13 23:13:44 +03:00
parent 0088f2b4e3
commit 00bf9705a9
2 changed files with 85 additions and 70 deletions

View file

@ -11,10 +11,11 @@
namespace type_check {
class ContextHolder;
template <nodes::Return::Kind kind> class ContextHolder;
class State {
friend ContextHolder;
friend ContextHolder<nodes::Return::Kind::BRING>;
friend ContextHolder<nodes::Return::Kind::RETURN>;
public:
struct VariableInfo {
@ -92,7 +93,7 @@ private:
// TODO: argument for property is returned type should be merged
// returns brought type, return type is merged with next context or with
// brought type in last context
nodes::MaybeType exit_context() {
nodes::MaybeType ExitContext(nodes::Return::Kind result_kind) {
Log::Context logc(log_, Log::Area::kTypeCheck);
if (contexts_.empty()) {
@ -129,7 +130,14 @@ private:
}
}
return brought_type;
switch (result_kind) {
case nodes::Return::Kind::BRING:
return brought_type;
case nodes::Return::Kind::RETURN:
return returned_type;
}
utils::unreachable();
}
public:
@ -239,7 +247,7 @@ private:
//
class ContextHolder {
template <nodes::Return::Kind kind> class ContextHolder {
public:
ContextHolder(State &state, const utils::Pos &pos,
nodes::MaybeType *context_exit_type)
@ -255,9 +263,9 @@ public:
~ContextHolder() {
if (context_exit_type_) {
*context_exit_type_ = state_.exit_context();
*context_exit_type_ = state_.ExitContext(kind);
} else {
state_.exit_context();
state_.ExitContext(kind);
}
}

View file

@ -148,18 +148,16 @@ Result CheckTask<nodes::Condition>::operator()(const nodes::Condition &expr,
return TypeCheckFromArgs(expr_result.value().Get(), args, current_pos);
}
// NOTE: change to ranges in future
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 ??
//
MaybeResult interval_result;
MaybeResult variable_result;
Result expression_result = Run(expr.expr, {expr.expr});
switch (expr.kind) {
@ -168,74 +166,67 @@ Result CheckTask<nodes::Loop>::operator()(const nodes::Loop &expr,
case nodes::Loop::WHILE:
Run(expr.condition.value(), Args{expr.condition.value()}.ExpectBuiltin(
builtin::Type::BOOL, executor));
// --- type check is independent from loop itself ---
// if (condition_result.value().is_invalid()) {
// return condition_result.value();
// }
break;
case nodes::Loop::FOR:
// TODO: expect range ??
interval_result =
Run(expr.interval.value(), Args{expr.interval.value()}.ExpectBuiltin(
builtin::Type::ARRAY, executor));
Run(expr.interval.value(),
Args{expr.interval.value()}.ExpectBuiltin(
builtin::Type::ARRAY /* NOTE: range in future */, executor));
if (interval_result.value().is_invalid()) {
// --- type check is independent from loop itself ---
// return interval_result.value();
break;
}
variable_result =
Run(expr.variable.value(),
Args{expr.variable.value()}.Expect(
interval_result.value().Get().get()->get_parameter_proxy(0)));
const auto range_elem_type =
interval_result.value().Get().get()->get_parameter_proxy(0);
// --- type check is independent from loop itself ---
// if (variable_result.value().is_invalid()) {
// return variable_result.value();
// }
variable_result = Run(expr.variable.value(),
Args{expr.variable.value()}.Expect(
range_elem_type)); // TODO: or pass type ??
break;
}
if (expression_result.is_invalid()) { // TODO: log invalid
return expression_result;
if (expression_result.is_invalid()) {
TypeCheckError("Invalid loop expression", PosOf(expr.expr));
return Result::invalid();
}
// TODO: modifier checks ??, modifiers ??
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;
for (const auto &elem_expr : expr.exprs) {
// elements should have same type, but type is not expected
// elements should have the same type, but no type expected
auto expr_result = Run(elem_expr, {elem_expr});
if (!last_expr_result.has_value()) {
if (expr_result.is_invalid()) {
TypeCheckError("Invalid array element", PosOf(args.current_id));
continue;
}
if (not last_expr_result.has_value()) {
last_expr_result = expr_result;
} else {
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
// type is not modified to max possible type deduction
}
}
}
if (!last_expr_result.has_value()) {
if (not last_expr_result.has_value()) {
TypeCheckError("Array with zero elements", current_pos);
return Result::invalid();
}
@ -248,15 +239,16 @@ Result CheckTask<nodes::Container>::CheckArray(const nodes::Container &expr,
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;
{
ContextHolder context_holder(
state<State>(), current_pos,
&context_exit_type); // TODO: is brought type returned
// brought type returned
ContextHolder<nodes::Return::Kind::BRING> context_holder(
state<State>(), current_pos, &context_exit_type);
for (const auto &elem_expr : expr.exprs) {
// result types in block are discarded
@ -269,8 +261,7 @@ Result CheckTask<nodes::Container>::CheckBlock(const nodes::Container &expr,
? Result(context_exit_type.value())
: Result(state<Types>().primitive(builtin::Type::UNIT));
return TypeCheckFromArgs(
state<Types>().add_array_of(block_brought_type.Get()), args, current_pos);
return TypeCheckFromArgs(block_brought_type.Get(), args, current_pos);
}
Result CheckTask<nodes::Container>::operator()(const nodes::Container &expr,
@ -288,24 +279,25 @@ 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});
if (returned_result.is_invalid()) {
return returned_result;
return Result::invalid();
}
switch (expr.kind) {
case nodes::Return::BRING:
if (state<State>().BringType(returned_result.Get())) {
if (not 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>().ReturnType(returned_result.Get())) {
if (not state<State>().ReturnType(returned_result.Get())) {
TypeCheckError("Different returned type to current one", current_pos);
return Result::invalid();
}
@ -316,6 +308,8 @@ Result CheckTask<nodes::Return>::operator()(const nodes::Return &expr,
current_pos);
}
// <------ NOTE: CHECK ENDED THERE
// TODO: warning if name is same to package prefix, function prefix, etc. ??
Result
CheckTask<nodes::NameDefinition>::operator()(const nodes::NameDefinition &expr,
@ -351,46 +345,51 @@ CheckTask<nodes::NameDefinition>::operator()(const nodes::NameDefinition &expr,
current_pos);
}
// NOTE: CHECKED
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}.ExpectBuiltin(builtin::Type::INDEX, executor));
// TODO: check expect for parametrized type without parametears
auto value_result =
Run(expr.value,
Args{expr.value}.ExpectBuiltin(builtin::Type::ARRAY, executor));
if (index_result.is_invalid()) {
return index_result;
return Result::invalid();
}
if (value_result.is_invalid()) {
return value_result;
return Result::invalid();
}
// TODO: modifier checks ??
// NOTE: 0 - type of array
return TypeCheckFromArgs(value_result.Get().get()->get_parameter_proxy(0),
args, current_pos);
}
// NOTE: CHECKED
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);
//
// TODO: check expect for parametrized type without parametears
auto value_result =
Run(expr.value,
Args{expr.value}.ExpectBuiltin(builtin::Type::TUPLE, executor));
if (value_result.is_invalid()) {
return value_result;
return Result::invalid();
}
size_t index = *Ext(expr.index)
@ -398,12 +397,11 @@ Result CheckTask<nodes::Access>::CheckTupleAccess(const nodes::Access &expr,
.get<size_t>() // Index type
.value();
// TODO: modifier checks ??
return TypeCheckFromArgs(value_result.Get().get()->get_parameter_proxy(index),
args, current_pos);
}
// NOTE: CHECKED
Result CheckTask<nodes::Access>::operator()(const nodes::Access &expr,
const Args &args) {
Log::Context logc(executor.log(), Log::Area::kTypeCheck);
@ -416,12 +414,14 @@ Result CheckTask<nodes::Access>::operator()(const nodes::Access &expr,
}
}
// NOTE: CHECKED
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 TypeCheckFromArgs(state<Types>().primitive(builtin::Type::UNIT), args,
current_pos);
}
@ -429,28 +429,27 @@ Result CheckTask<nodes::LoopControl>::operator()(const nodes::LoopControl &expr,
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);
//
// TODO: expext Optional or Result ??
auto modified_result = Run(expr.expr, {expr.expr});
if (modified_result.is_invalid()) {
return Result::invalid();
}
if (nodes::utils::is_suffix_modifier(
expr.modifier)) { // optional, result
// '?' - open optional / result in ->
// (execute or not execute pattern
// matching expression) / (value /
// return) (TODO: alternative for bring)
if (nodes::utils::is_suffix_modifier(expr.modifier)) { // optional, result
// '?' - open optional / result in -> (execute or not execute pattern
// matching expression) / (value / return) (TODO: alternative for bring)
// '!' - open optional / result -> value / panic
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));
break;
default:
@ -458,7 +457,9 @@ Result CheckTask<nodes::ModifierExpression>::operator()(
return Result::invalid();
}
} else {
// TODO: check that modifier can be applied
// NOTE: other modifiers applied instead of current one
// TODO: check thatmodification is possible
modified_result.Set(state<Types>().add_modification_of(
modified_result.Get(), expr.modifier));
}
@ -937,16 +938,22 @@ Result CheckTask<nodes::Lambda>::operator()(const nodes::Lambda &expr,
return TypeCheckFromArgs(expected_type, args, current_pos);
} // IN PROGRESS
// NOTE: CHECKED
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));
}
// NOTE: CHECKED
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));
}