From e4f2053ca68746bca391d494ac88bda38bf4bfb5 Mon Sep 17 00:00:00 2001 From: Laria Carolin Chabowski Date: Sat, 26 Nov 2022 23:06:55 +0100 Subject: [PATCH] Fix apfl_join_strings manipulating the parts list --- src/apfl.h | 2 + src/context.c | 128 +++++++++++++++++++++-------------- src/functional-tests/join.at | 13 ++++ 3 files changed, 93 insertions(+), 50 deletions(-) diff --git a/src/apfl.h b/src/apfl.h index 5e11830..e4382f9 100644 --- a/src/apfl.h +++ b/src/apfl.h @@ -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 diff --git a/src/context.c b/src/context.c index af997fc..bddb207 100644 --- a/src/context.c +++ b/src/context.c @@ -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) { diff --git a/src/functional-tests/join.at b/src/functional-tests/join.at index ee8530d..af1cf77 100644 --- a/src/functional-tests/join.at +++ b/src/functional-tests/join.at @@ -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