Fix apfl_join_strings manipulating the parts list
This commit is contained in:
parent
0febf48401
commit
e4f2053ca6
3 changed files with 93 additions and 50 deletions
|
|
@ -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
|
||||
|
|
|
|||
128
src/context.c
128
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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Reference in a new issue