mirror of
https://github.com/roc-lang/roc.git
synced 2025-12-23 08:48:03 +00:00
Completed integration of list.drop_at into interpreter, working on record arg handling to finish list.sublist
This commit is contained in:
parent
4555f2060c
commit
c3b87ff8cf
7 changed files with 231 additions and 0 deletions
|
|
@ -166,6 +166,12 @@ fn replaceStrIsEmptyWithLowLevel(env: *ModuleEnv) !std.ArrayList(CIR.Def.Idx) {
|
|||
if (env.common.findIdent("list_get_unsafe")) |list_get_unsafe_ident| {
|
||||
try low_level_map.put(list_get_unsafe_ident, .list_get_unsafe);
|
||||
}
|
||||
if (env.common.findIdent("Builtin.List.drop_at")) |list_drop_at_ident| {
|
||||
try low_level_map.put(list_drop_at_ident, .list_drop_at);
|
||||
}
|
||||
if (env.common.findIdent("Builtin.List.sublist")) |list_sublist_ident| {
|
||||
try low_level_map.put(list_sublist_ident, .list_sublist);
|
||||
}
|
||||
if (env.common.findIdent("Builtin.Bool.is_eq")) |bool_is_eq_ident| {
|
||||
try low_level_map.put(bool_is_eq_ident, .bool_is_eq);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -132,6 +132,9 @@ Builtin :: [].{
|
|||
True
|
||||
}
|
||||
|
||||
drop_at : List(a), U64 -> List(a)
|
||||
|
||||
sublist : List(a), {start : U64, len : U64} -> List(a)
|
||||
}
|
||||
|
||||
Bool := [False, True].{
|
||||
|
|
|
|||
|
|
@ -475,6 +475,8 @@ pub const Expr = union(enum) {
|
|||
list_concat,
|
||||
list_with_capacity,
|
||||
list_sort_with,
|
||||
list_drop_at,
|
||||
list_sublist,
|
||||
|
||||
// Bool operations
|
||||
bool_is_eq,
|
||||
|
|
|
|||
|
|
@ -163,6 +163,9 @@ pub const CommonIdents = extern struct {
|
|||
// from_utf8 error payload fields (BadUtf8 record)
|
||||
problem: Ident.Idx,
|
||||
index: Ident.Idx,
|
||||
// sublist argument payload fields
|
||||
// sublist_start: Ident.Idx,
|
||||
// sublist_len: Ident.Idx,
|
||||
|
||||
/// Insert all well-known identifiers into a CommonEnv.
|
||||
/// Use this when creating a fresh ModuleEnv from scratch.
|
||||
|
|
@ -228,6 +231,9 @@ pub const CommonIdents = extern struct {
|
|||
// from_utf8 error payload fields (BadUtf8 record)
|
||||
.problem = try common.insertIdent(gpa, Ident.for_text("problem")),
|
||||
.index = try common.insertIdent(gpa, Ident.for_text("index")),
|
||||
// sublist argument payload fields
|
||||
// .sublist_start = try common.insertIdent(gpa, Ident.for_text("start")),
|
||||
// .sublist_len = try common.insertIdent(gpa, Ident.for_text("len")),
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -296,6 +302,9 @@ pub const CommonIdents = extern struct {
|
|||
// from_utf8 error payload fields (BadUtf8 record)
|
||||
.problem = common.findIdent("problem") orelse unreachable,
|
||||
.index = common.findIdent("index") orelse unreachable,
|
||||
// sublist argument payload fields
|
||||
// .sublist_start = common.findIdent("start") orelse unreachable,
|
||||
// .sublist_len = common.findIdent("len") orelse unreachable,
|
||||
};
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1729,6 +1729,122 @@ pub const Interpreter = struct {
|
|||
out.is_initialized = true;
|
||||
return out;
|
||||
},
|
||||
.list_drop_at => {
|
||||
// List.drop_at : List(a), U64 -> List(a)
|
||||
std.debug.assert(args.len == 2); // low-level .list_drop_at expects 2 argument
|
||||
|
||||
const list_arg = args[0];
|
||||
const drop_index_arg = args[1];
|
||||
const drop_index: u64 = @intCast(drop_index_arg.asI128());
|
||||
|
||||
std.debug.assert(list_arg.layout.tag == .list or list_arg.layout.tag == .list_of_zst);
|
||||
|
||||
const roc_list: *const builtins.list.RocList = @ptrCast(@alignCast(list_arg.ptr.?));
|
||||
|
||||
// Get element layout from the list layout
|
||||
const elem_layout_idx = list_arg.layout.data.list;
|
||||
const elem_layout = self.runtime_layout_store.getLayout(elem_layout_idx);
|
||||
const elem_size = 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();
|
||||
|
||||
// Set up context for refcount callbacks
|
||||
var refcount_context = RefcountContext{
|
||||
.layout_store = &self.runtime_layout_store,
|
||||
.elem_layout = elem_layout,
|
||||
.roc_ops = roc_ops,
|
||||
};
|
||||
|
||||
// Return list with element at index dropped
|
||||
const result_list = builtins.list.listDropAt(
|
||||
roc_list.*,
|
||||
elem_alignment_u32,
|
||||
elem_size,
|
||||
elements_refcounted,
|
||||
drop_index,
|
||||
if (elements_refcounted) @ptrCast(&refcount_context) else null,
|
||||
if (elements_refcounted) &listElementInc else &builtins.list.rcNone,
|
||||
if (elements_refcounted) @ptrCast(&refcount_context) else null,
|
||||
if (elements_refcounted) &listElementDec else &builtins.list.rcNone,
|
||||
roc_ops,
|
||||
);
|
||||
|
||||
// Allocate space for the result list
|
||||
const result_layout = list_arg.layout;
|
||||
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;
|
||||
},
|
||||
.list_sublist => {
|
||||
// List.sublist : List(a), {start : U64, len : U64} -> List(a)
|
||||
std.debug.assert(args.len == 2); // low-level .list_sublist expects 2 argument
|
||||
|
||||
// Check and extract first element as a typed RocList
|
||||
const list_arg = args[0];
|
||||
std.debug.assert(list_arg.layout.tag == .list or list_arg.layout.tag == .list_of_zst);
|
||||
const roc_list: *const builtins.list.RocList = @ptrCast(@alignCast(list_arg.ptr.?));
|
||||
|
||||
// Access second argument as a record and extract its specific fields
|
||||
const sublist_config = args[1].asRecord(&self.runtime_layout_store) catch unreachable;
|
||||
const sublist_start_index = 0; // sublist_config.findFieldIndex(self.env.idents.sublist_start).?;
|
||||
const sublist_start_stack = sublist_config.getFieldByIndex(sublist_start_index) catch unreachable;
|
||||
const sublist_len_index = 1; //sublist_config.findFieldIndex(self.env.idents.sublist_len).?;
|
||||
const sublist_len_stack = sublist_config.getFieldByIndex(sublist_len_index) catch unreachable;
|
||||
const sublist_start: u64 = @intCast(sublist_start_stack.asI128());
|
||||
const sublist_len: u64 = @intCast(sublist_len_stack.asI128());
|
||||
std.debug.print("\nConfig Record: {{start: {d}, len: {d} }}\n", .{ sublist_start, sublist_len });
|
||||
|
||||
// Get element layout from the list layout
|
||||
const elem_layout_idx = list_arg.layout.data.list;
|
||||
const elem_layout = self.runtime_layout_store.getLayout(elem_layout_idx);
|
||||
const elem_size = 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();
|
||||
|
||||
// Set up context for refcount callbacks
|
||||
var refcount_context = RefcountContext{
|
||||
.layout_store = &self.runtime_layout_store,
|
||||
.elem_layout = elem_layout,
|
||||
.roc_ops = roc_ops,
|
||||
};
|
||||
|
||||
// Return list with element at index dropped
|
||||
const result_list = builtins.list.listSublist(
|
||||
roc_list.*,
|
||||
elem_alignment_u32,
|
||||
elem_size,
|
||||
elements_refcounted,
|
||||
sublist_start,
|
||||
sublist_len,
|
||||
if (elements_refcounted) @ptrCast(&refcount_context) else null,
|
||||
if (elements_refcounted) &listElementDec else &builtins.list.rcNone,
|
||||
roc_ops,
|
||||
);
|
||||
|
||||
// Allocate space for the result list
|
||||
const result_layout = list_arg.layout;
|
||||
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;
|
||||
},
|
||||
// Bool operations
|
||||
.bool_is_eq => {
|
||||
// Bool.is_eq : Bool, Bool -> Bool
|
||||
|
|
|
|||
|
|
@ -52,6 +52,13 @@ test "list refcount builtins - phase 12 limitation documented" {
|
|||
// - "e_low_level_lambda - List.with_capacity without capacity, of str (refcounted elements) can concat"
|
||||
// - "e_low_level_lambda - List.with_capacity of zero-sized type creates empty list"
|
||||
//
|
||||
// - "e_low_level_lambda - List.drop_at on an empty list at index 0"
|
||||
// - "e_low_level_lambda - List.drop_at on an empty list at index >0"
|
||||
// - "e_low_level_lambda - List.drop_at on non-empty list"
|
||||
// - "e_low_level_lambda - List.drop_at out of bounds on non-empty list"
|
||||
// - "e_low_level_lambda - List.drop_at on refcounted List(Str)"
|
||||
// - "e_low_level_lambda - List.drop_at on refcounted List(List(Str))"
|
||||
//
|
||||
// interpreter_style_test.zig:
|
||||
// - "interpreter: match list pattern destructures"
|
||||
// - "interpreter: match list rest binds slice"
|
||||
|
|
|
|||
|
|
@ -755,6 +755,94 @@ test "e_low_level_lambda - List.with_capacity of zero-sized type creates empty l
|
|||
try testing.expectEqual(@as(i128, 0), len_value);
|
||||
}
|
||||
|
||||
test "e_low_level_lambda - List.drop_at on an empty list at index 0" {
|
||||
const src =
|
||||
\\x = List.drop_at([], 0)
|
||||
\\len = List.len(x)
|
||||
;
|
||||
|
||||
const len_value = try evalModuleAndGetInt(src, 1);
|
||||
try testing.expectEqual(@as(i128, 0), len_value);
|
||||
}
|
||||
|
||||
test "e_low_level_lambda - List.drop_at on an empty list at index >0" {
|
||||
const src =
|
||||
\\x = List.drop_at([], 10)
|
||||
\\len = List.len(x)
|
||||
;
|
||||
|
||||
const len_value = try evalModuleAndGetInt(src, 1);
|
||||
try testing.expectEqual(@as(i128, 0), len_value);
|
||||
}
|
||||
|
||||
test "e_low_level_lambda - List.drop_at on non-empty list" {
|
||||
const src =
|
||||
\\x = List.drop_at([1, 2, 3], 0)
|
||||
\\len = List.len(x)
|
||||
\\first = List.get(x, 0)
|
||||
;
|
||||
|
||||
const len_value = try evalModuleAndGetInt(src, 1);
|
||||
try testing.expectEqual(@as(i128, 2), len_value);
|
||||
|
||||
const value = try evalModuleAndGetString(src, 2, test_allocator);
|
||||
defer test_allocator.free(value);
|
||||
try testing.expectEqualStrings("Ok(2)", value);
|
||||
}
|
||||
|
||||
test "e_low_level_lambda - List.drop_at out of bounds on non-empty list" {
|
||||
const src =
|
||||
\\x = List.drop_at([1, 2, 3, 4, 5], 10)
|
||||
\\len = List.len(x)
|
||||
;
|
||||
|
||||
const len_value = try evalModuleAndGetInt(src, 1);
|
||||
try testing.expectEqual(@as(i128, 5), len_value);
|
||||
}
|
||||
|
||||
test "e_low_level_lambda - List.drop_at on refcounted List(Str)" {
|
||||
const src =
|
||||
\\x = List.drop_at(["cat", "chases", "rat"], 1)
|
||||
\\len = List.len(x)
|
||||
\\second = List.get(x, 1)
|
||||
;
|
||||
|
||||
const len_value = try evalModuleAndGetInt(src, 1);
|
||||
try testing.expectEqual(@as(i128, 2), len_value);
|
||||
|
||||
const value = try evalModuleAndGetString(src, 2, test_allocator);
|
||||
defer test_allocator.free(value);
|
||||
try testing.expectEqualStrings("Ok(\"rat\")", value);
|
||||
}
|
||||
|
||||
test "e_low_level_lambda - List.drop_at on refcounted List(List(Str))" {
|
||||
const src =
|
||||
\\x = List.drop_at([["two", "words"], [], ["a", "four", "word", "list"]], 1)
|
||||
\\len = List.len(x)
|
||||
\\second = Try.ok_or(List.get(x, 1), [])
|
||||
\\elt_len = List.len(second)
|
||||
;
|
||||
|
||||
const len_value = try evalModuleAndGetInt(src, 1);
|
||||
try testing.expectEqual(@as(i128, 2), len_value);
|
||||
|
||||
const elt_len_value = try evalModuleAndGetInt(src, 3);
|
||||
try testing.expectEqual(@as(i128, 4), elt_len_value);
|
||||
}
|
||||
|
||||
test "e_low_level_lambda - List.sublist on non-empty list" {
|
||||
const src =
|
||||
\\x = List.sublist([0, 1, 2, 3, 4], {len: 10, start: 3})
|
||||
\\len = List.len(x)
|
||||
;
|
||||
|
||||
const len_value = try evalModuleAndGetInt(src, 1);
|
||||
try testing.expectEqual(@as(i128, 2), len_value);
|
||||
|
||||
// const elt_len_value = try evalModuleAndGetInt(src, 3);
|
||||
// try testing.expectEqual(@as(i128, 4), elt_len_value);
|
||||
}
|
||||
|
||||
test "e_low_level_lambda - Dec.to_str returns string representation of decimal" {
|
||||
const src =
|
||||
\\a : Dec
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue