Fix apfl_join_strings manipulating the parts list

This commit is contained in:
Laria 2022-11-26 23:06:55 +01:00
parent 0febf48401
commit e4f2053ca6
3 changed files with 93 additions and 50 deletions

View file

@ -658,6 +658,8 @@ enum apfl_value_type apfl_get_type(apfl_ctx, apfl_stackidx);
void apfl_drop(apfl_ctx, apfl_stackidx);
// Move a value to the top of the stack
void apfl_move_to_top_of_stack(apfl_ctx, apfl_stackidx);
// Move count values to the top of the stack in order
void apfl_multi_move_to_top_of_stack(apfl_ctx ctx, size_t count, apfl_stackidx *indices);
// Copy a value to the top of the stack
void apfl_copy(apfl_ctx ctx, apfl_stackidx index);
// Push a nil onto the stack

View file

@ -420,31 +420,48 @@ apfl_drop(apfl_ctx ctx, apfl_stackidx index)
}
}
static bool
current_stack_move_to_top(apfl_ctx ctx, apfl_stackidx index)
bool
current_stack_multi_move_to_top(apfl_ctx ctx, size_t count, apfl_stackidx *indices)
{
struct stack *stack = current_value_stack(ctx);
struct apfl_value val;
if (!stack_get_and_adjust_index(stack, &val, &index)) {
return false;
for (size_t i = 0; i < count; i++) {
if (!stack_check_index(stack, &indices[i])) {
return false;
}
}
size_t absindex = (size_t)index;
for (size_t i = 0; i < count; i++) {
// If we're here, index is an absolute address and is guaranteed to be < len
assert(indices[i] >= 0);
size_t absindex = (size_t)indices[i];
assert(stack->len >= absindex+1);
// If we're here, index is an absolute address and is guaranteed to be < len
assert(stack->len >= absindex+1);
struct apfl_value val = stack->items[absindex];
memmove(
&stack->items[absindex + 1],
&stack->items[absindex],
stack->len - absindex - 1
);
stack->items[stack->len-1] = val;
memmove(
&stack->items[absindex],
&stack->items[absindex + 1],
sizeof(struct apfl_value) * (stack->len - absindex - 1)
);
stack->items[stack->len-1] = val;
for (size_t j = i + 1; j < count; j++) {
if (indices[j] >= indices[i]) {
indices[j]--;
}
}
}
return true;
}
static bool
current_stack_move_to_top(apfl_ctx ctx, apfl_stackidx index)
{
return current_stack_multi_move_to_top(ctx, 1, &index);
}
void
apfl_move_to_top_of_stack(apfl_ctx ctx, apfl_stackidx index)
{
@ -453,6 +470,14 @@ apfl_move_to_top_of_stack(apfl_ctx ctx, apfl_stackidx index)
}
}
void
apfl_multi_move_to_top_of_stack(apfl_ctx ctx, size_t count, apfl_stackidx *indices)
{
if (!current_stack_multi_move_to_top(ctx, count, indices)) {
apfl_raise_invalid_stackidx(ctx);
}
}
void
apfl_copy(apfl_ctx ctx, apfl_stackidx index)
{
@ -1251,40 +1276,49 @@ apfl_tostring(apfl_ctx ctx, apfl_stackidx index)
apfl_stack_drop(ctx, -2); // Drop original value
}
static void
join_strings_inner(apfl_ctx ctx, apfl_stackidx _glue, apfl_stackidx _parts)
void
apfl_join_strings(apfl_ctx ctx, apfl_stackidx glue, apfl_stackidx parts)
{
struct apfl_value glue_val = apfl_stack_must_get(ctx, _glue);
struct apfl_value parts_val = apfl_stack_must_get(ctx, _parts);
apfl_multi_move_to_top_of_stack(ctx, 2, (apfl_stackidx[]){parts, glue});
parts = -2;
glue = -1;
if (!apfl_value_add_as_tmproot(&ctx->gc, glue_val)) {
apfl_raise_alloc_error(ctx);
}
if (!apfl_value_add_as_tmproot(&ctx->gc, parts_val)) {
apfl_raise_alloc_error(ctx);
}
struct apfl_value *parts_val = stack_get_pointer(ctx, parts);
assert(parts_val != NULL /* Should not be null, we moved it to a known position on the stack */);
assert(apfl_stack_drop_multi(ctx, 2, (apfl_stackidx[]) { _glue, _parts }));
if (parts_val.type != VALUE_LIST) {
if (parts_val->type != VALUE_LIST) {
apfl_raise_const_error(ctx, APFL_RESULT_ERR, apfl_messages.not_a_list);
}
struct list_header *parts = parts_val.list;
apfl_tostring(ctx, glue);
struct apfl_string_view glue_sv = apfl_get_string(ctx, glue);
apfl_stack_must_push(ctx, glue_val);
apfl_tostring(ctx, -1);
struct apfl_string_view glue_sv = apfl_get_string(ctx, -1);
struct list_header **parts_list = &parts_val->list;
size_t total_length = 0;
for (size_t i = 0; i < parts->len; i++) {
apfl_stack_must_push(ctx, parts->items[i]);
apfl_tostring(ctx, -1);
parts->items[i] = apfl_stack_must_pop(ctx, -1);
for (size_t i = 0; i < (*parts_list)->len; i++) {
// Convert values to strings, if necessary
if (!VALUE_IS_A((*parts_list)->items[i], APFL_VALUE_STRING)) {
apfl_stack_must_push(ctx, (*parts_list)->items[i]);
apfl_tostring(ctx, -1);
if (!apfl_list_splice(
&ctx->gc,
parts_list,
i,
1,
stack_get_pointer(ctx, -1),
1
)) {
goto error;
}
apfl_stack_drop(ctx, -1);
}
struct apfl_string_view part_sv;
assert(get_string_view_of_value(&part_sv, parts->items[i]) /* Value should be a string at this point */);
assert(get_string_view_of_value(&part_sv, (*parts_list)->items[i]) /* Value should be a string at this point */);
total_length += part_sv.len;
@ -1298,7 +1332,7 @@ join_strings_inner(apfl_ctx ctx, apfl_stackidx _glue, apfl_stackidx _parts)
goto error;
}
for (size_t i = 0; i < parts->len; i++) {
for (size_t i = 0; i < (*parts_list)->len; i++) {
if (i > 0) {
if (!apfl_string_builder_append(&sb, glue_sv)) {
goto error;
@ -1306,7 +1340,7 @@ join_strings_inner(apfl_ctx ctx, apfl_stackidx _glue, apfl_stackidx _parts)
}
struct apfl_string_view part_sv;
assert(get_string_view_of_value(&part_sv, parts->items[i]) /* Value should be a string at this point */);
assert(get_string_view_of_value(&part_sv, (*parts_list)->items[i]) /* Value should be a string at this point */);
if (!apfl_string_builder_append(&sb, part_sv)) {
goto error;
@ -1321,24 +1355,18 @@ join_strings_inner(apfl_ctx ctx, apfl_stackidx _glue, apfl_stackidx _parts)
goto error;
}
apfl_drop(ctx, -2); // Drop the glue from the stack
// Drop the glue and list from the stack
apfl_drop(ctx, -2);
apfl_drop(ctx, -2);
return;
error:
apfl_drop(ctx, -1); // Drop the glue from the stack
// Drop the glue and list from the stack
apfl_drop(ctx, -1);
apfl_drop(ctx, -1);
apfl_raise_alloc_error(ctx);
}
void
apfl_join_strings(apfl_ctx ctx, apfl_stackidx glue, apfl_stackidx parts)
{
size_t tmproots = apfl_gc_tmproots_begin(&ctx->gc);
join_strings_inner(ctx, glue, parts);
apfl_gc_tmproots_restore(&ctx->gc, tmproots);
}
bool
apfl_is_truthy(apfl_ctx ctx, apfl_stackidx index)
{

View file

@ -17,6 +17,12 @@ print (join 1 ['foo 'bar])
print (join 1 ['foo 'bar 'baz])
print (join 1 ['foo 1 true [] [->]])
foo = [1 2 3]
bar = 0
print (join bar foo)
dump foo
dump bar
===== output =====
foo
@ -33,3 +39,10 @@ foo
foo1bar
foo1bar1baz
foo111true1[]1[->]
10203
[
1
2
3
]
0