minishell/parser/src/parser/parser_versions.c

128 lines
3.8 KiB
C

/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* parser_versions.c :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: maiboyer <maiboyer@student.42.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2024/09/13 13:42:50 by maiboyer #+# #+# */
/* Updated: 2024/09/19 22:17:04 by maiboyer ### ########.fr */
/* */
/* ************************************************************************** */
#include "parser/inner/parser_inner.h"
bool _parser_compare_inner(t_parser *self, \
t_error_status a, t_error_status b, t_error_comparison *ret)
{
(void)(self);
if (!a.is_in_error && b.is_in_error)
{
if (a.cost < b.cost)
return (*ret = ECTakeLeft, true);
else
return (*ret = ECPreferLeft, true);
}
if (a.is_in_error && !b.is_in_error)
{
if (b.cost < a.cost)
return (*ret = ECTakeRight, true);
else
return (*ret = ECPreferRight, true);
}
if (a.cost < b.cost)
{
if ((b.cost - a.cost) * (1 + a.node_count) > MAX_COST_DIFFERENCE)
return (*ret = ECTakeLeft, true);
else
return (*ret = ECPreferLeft, true);
}
return (false);
}
t_error_comparison ts_parser__compare_versions(t_parser *self,
t_error_status a, t_error_status b)
{
t_error_comparison ret;
if (_parser_compare_inner(self, a, b, &ret))
return (ret);
if (b.cost < a.cost)
{
if ((a.cost - b.cost) * (1 + b.node_count) > MAX_COST_DIFFERENCE)
return (ECTakeRight);
else
return (ECPreferRight);
}
if (a.dynamic_precedence > b.dynamic_precedence)
return (ECPreferLeft);
if (b.dynamic_precedence > a.dynamic_precedence)
return (ECPreferRight);
return (ECNone);
}
t_error_status ts_parser__version_status(t_parser *self,
t_stack_version version)
{
t_u32 cost;
bool is_paused;
cost = ts_stack_error_cost(self->stack, version);
is_paused = ts_stack_is_paused(self->stack, version);
if (is_paused)
cost += ERROR_COST_PER_SKIPPED_TREE;
return ((t_error_status){.cost = cost,
.node_count = ts_stack_node_count_since_error(self->stack, version),
.dynamic_precedence = ts_stack_dynamic_precedence(self->stack, version),
.is_in_error = is_paused || ts_stack_state(self->stack,
version) == ERROR_STATE});
}
bool _better_version_end(\
t_parser *self, t_stack_version version, \
t_length position, t_error_status status)
{
t_stack_version i;
t_stack_version n;
t_error_comparison cmp;
t_error_status status_i;
i = 0;
n = ts_stack_version_count(self->stack);
while (i < n)
{
if (i == version || !ts_stack_is_active(self->stack, i)
|| ts_stack_position(self->stack, i).bytes < position.bytes)
{
i++;
continue ;
}
status_i = ts_parser__version_status(self, i);
cmp = ts_parser__compare_versions(self, status, status_i);
if (cmp == ECTakeRight)
return (true);
if (cmp == ECPreferRight && ts_stack_can_merge(self->stack, i, version))
return (true);
i++;
}
return (false);
}
bool ts_parser__better_version_exists(t_parser *self,
t_stack_version version, bool is_in_error, t_u32 cost)
{
t_length position;
t_error_status status;
if (self->finished_tree
&& ts_subtree_error_cost(self->finished_tree) <= cost)
return (true);
position = ts_stack_position(self->stack, version);
status = (t_error_status){
.cost = cost,
.is_in_error = is_in_error,
.dynamic_precedence = ts_stack_dynamic_precedence(self->stack, version),
.node_count = ts_stack_node_count_since_error(self->stack, version),
};
return (_better_version_end(self, version, position, status));
}