Working on implementing List.append in low level interpreter

This commit is contained in:
Edwin Santos 2025-11-27 21:25:29 -05:00
parent b5eb58ba3d
commit 882bc163ae
6 changed files with 92 additions and 7 deletions

View file

@ -130,6 +130,9 @@ fn replaceStrIsEmptyWithLowLevel(env: *ModuleEnv) !std.ArrayList(CIR.Def.Idx) {
if (env.common.findIdent("Builtin.List.concat")) |list_concat_ident| {
try low_level_map.put(list_concat_ident, .list_concat);
}
if (env.common.findIdent("Builtin.List.append")) |list_append_ident| {
try low_level_map.put(list_append_ident, .list_append);
}
if (env.common.findIdent("list_get_unsafe")) |list_get_unsafe_ident| {
try low_level_map.put(list_get_unsafe_ident, .list_get_unsafe);
}

View file

@ -44,6 +44,8 @@ Builtin :: [].{
True
}
append : List(a), a -> List(a)
first : List(item) -> Try(item, [ListWasEmpty])
first = |list| List.get(list, 0)

View file

@ -11,10 +11,10 @@ const RocOps = @import("host_abi.zig").RocOps;
const RocStr = @import("str.zig").RocStr;
const increfDataPtrC = utils.increfDataPtrC;
const Opaque = ?[*]u8;
pub const Opaque = ?[*]u8;
const EqFn = *const fn (Opaque, Opaque) callconv(.c) bool;
const CompareFn = *const fn (Opaque, Opaque, Opaque) callconv(.c) u8;
const CopyFn = *const fn (Opaque, Opaque) callconv(.c) void;
pub const CopyFn = *const fn (Opaque, Opaque) callconv(.c) void;
const Inc = *const fn (?*anyopaque, ?[*]u8) callconv(.c) void;
const IncN = *const fn (?*anyopaque, ?[*]u8, usize) callconv(.c) void;
@ -531,7 +531,7 @@ pub fn listAppendUnsafe(
list: RocList,
element: Opaque,
element_width: usize,
copy: CopyFn,
// copy: CopyFn,
) callconv(.c) RocList {
const old_length = list.len();
var output = list;
@ -540,22 +540,23 @@ pub fn listAppendUnsafe(
if (output.bytes) |bytes| {
if (element) |source| {
const target = bytes + old_length * element_width;
copy(target, source);
@memcpy(target[0..element_width], source[0..element_width]);
}
}
return output;
}
fn listAppend(
pub fn listAppend(
list: RocList,
alignment: u32,
element: Opaque,
element_width: usize,
elements_refcounted: bool,
inc_context: ?*anyopaque,
inc: Inc,
update_mode: UpdateMode,
copy: CopyFn,
// copy: CopyFn,
roc_ops: *RocOps,
) callconv(.c) RocList {
const with_capacity = listReserve(
@ -564,11 +565,12 @@ fn listAppend(
1,
element_width,
elements_refcounted,
inc_context,
inc,
update_mode,
roc_ops,
);
return listAppendUnsafe(with_capacity, element, element_width, copy);
return listAppendUnsafe(with_capacity, element, element_width); // copy
}
/// Directly mutate the given list to push an element onto the end, and then return it.

View file

@ -464,6 +464,7 @@ pub const Expr = union(enum) {
list_is_empty,
list_get_unsafe,
list_concat,
list_append,
// Set operations
set_is_empty,

View file

@ -3423,6 +3423,73 @@ pub const Interpreter = struct {
out.is_initialized = true;
return out;
},
// .list_append => {
// // List.append: List(a), a -> List(a)
// std.debug.assert(args.len == 2); // low-level .list_get_unsafe expects 2 arguments
//
// const roc_list_arg = args[0];
// const elt_arg = args[1];
//
// std.debug.assert(roc_list_arg.ptr != null); // low-level .list_get_unsafe expects non-null list pointer
//
// // Extract element layout from List(a)
// std.debug.assert(roc_list_arg.layout.tag == .list or roc_list_arg.layout.tag == .list_of_zst); // low-level .list_get_unsafe expects list layout
//
// const roc_list: *const builtins.list.RocList = @ptrCast(@alignCast(roc_list_arg.ptr.?));
//
// // const append_elt: *const builtins.list.Opaque = @ptrCast(@alignCast(elt_arg.ptr.?));
//
// // Get element layout
// const elem_layout_idx = roc_list_arg.layout.data.list;
// const elem_layout = self.runtime_layout_store.getLayout(elem_layout_idx);
// const elem_size: u32 = self.runtime_layout_store.layoutSize(elem_layout);
// const elem_alignment = elem_layout.alignment(self.runtime_layout_store.targetUsize()).toByteUnits();
// const elem_alignment_u32: u32 = @intCast(elem_alignment);
//
// // Determine if elements are refcounted
// const elements_refcounted = elem_layout.isRefcounted();
//
// var temp_ptr: [32]u8 align(@alignOf(u128)) = undefined;
//
// try elt_arg.copyToPtr(&self.runtime_layout_store, &temp_ptr, roc_ops);
//
// const append_elt: *const builtins.list.Opaque = @ptrCast(@alignCast(&temp_ptr));
//
// // Determine if list can be mutated in place
// const update_mode = if (roc_list.isUnique()) builtins.utils.UpdateMode.InPlace else builtins.utils.UpdateMode.Immutable;
//
// // Set up context for refcount callbacks
// var refcount_context = RefcountContext{
// .layout_store = &self.runtime_layout_store,
// .elem_layout = elem_layout,
// .roc_ops = roc_ops,
// };
//
// // const sized_copy = struct {
// // const item_size = elem_size;
// // fn copy_fn(target: builtins.list.Opaque, src: builtins.list.Opaque) callconv(.c) void {
// // const target_ptr: [*]u8 = target.?;
// // const src_ptr: [*]u8 = src.?;
// // @memcpy(target_ptr, src_ptr[0..item_size]);
// // }
// // };
//
// const result_list = builtins.list.listAppend(roc_list.*, elem_alignment_u32, append_elt.*, elem_size, elements_refcounted, if (elements_refcounted) @ptrCast(&refcount_context) else null, if (elements_refcounted) &listElementInc else &builtins.list.rcNone, update_mode, roc_ops);
//
// // Allocate space for the result list
// const result_layout = roc_list_arg.layout; // Same layout as input
// var out = try self.pushRaw(result_layout, 0);
// out.is_initialized = false;
//
// // Copy the result list structure to the output
// const result_ptr: *builtins.list.RocList = @ptrCast(@alignCast(out.ptr.?));
// result_ptr.* = result_list;
//
// out.is_initialized = true;
// return out;
// // return error.Crash;
// },
.set_is_empty => {
// TODO: implement Set.is_empty
self.triggerCrash("Set.is_empty not yet implemented", false, roc_ops);

View file

@ -666,6 +666,16 @@ test "e_low_level_lambda - List.concat with empty string list" {
try testing.expectEqual(@as(i128, 3), len_value);
}
test "e_low_level_lambda - List.append on non-empty list" {
const src =
\\x = List.append([0, 1, 2, 3], 4)
\\len = List.len(x)
;
const len_value = try evalModuleAndGetInt(src, 1);
try testing.expectEqual(@as(i128, 3), len_value);
}
test "e_low_level_lambda - Dec.to_str returns string representation of decimal" {
const src =
\\a : Dec