diff --git a/src/build/roc/Builtin.roc b/src/build/roc/Builtin.roc index dcdf0f5452..70a40deb7e 100644 --- a/src/build/roc/Builtin.roc +++ b/src/build/roc/Builtin.roc @@ -135,6 +135,35 @@ Builtin :: [].{ drop_at : List(a), U64 -> List(a) sublist : List(a), {start : U64, len : U64} -> List(a) + + take_first : List(a), U64 -> List(a) + take_first = |list, n| { + config = {start: 0, len: n} + list.sublist( config) + } + + take_last : List(a), U64 -> List(a) + take_last = |list, n| { + len = List.len(list) + start = if (len < n) 0 else len - n + config = {start: start, len: len} + list.sublist( config) + } + + drop_first : List(a), U64 -> List(a) + drop_first = |list, n| { + len = List.len(list) + config = {start: n, len: len} + list.sublist( config) + } + + drop_last : List(a), U64 -> List(a) + drop_last = |list, n| { + len = List.len(list) + take_len = if (len < n) 0 else len - n + config = {start: 0, len: take_len} + list.sublist( config) + } } Bool := [False, True].{ diff --git a/src/canonicalize/ModuleEnv.zig b/src/canonicalize/ModuleEnv.zig index 6985b99b09..47bc4488c3 100644 --- a/src/canonicalize/ModuleEnv.zig +++ b/src/canonicalize/ModuleEnv.zig @@ -163,9 +163,6 @@ 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. @@ -231,9 +228,6 @@ 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")), }; } @@ -302,9 +296,6 @@ 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, }; } }; diff --git a/src/eval/interpreter.zig b/src/eval/interpreter.zig index 50c76a27a9..b2bbf9f780 100644 --- a/src/eval/interpreter.zig +++ b/src/eval/interpreter.zig @@ -1795,10 +1795,9 @@ pub const Interpreter = struct { // 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; + // When fields are alphabetically sorted, 0 will be `len` and 1 will be `start` + const sublist_start_stack = sublist_config.getFieldByIndex(1) catch unreachable; + const sublist_len_stack = sublist_config.getFieldByIndex(0) 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 }); diff --git a/src/eval/test/list_refcount_builtins.zig b/src/eval/test/list_refcount_builtins.zig index 0091b4f8ee..3638cd58d5 100644 --- a/src/eval/test/list_refcount_builtins.zig +++ b/src/eval/test/list_refcount_builtins.zig @@ -59,6 +59,11 @@ test "list refcount builtins - phase 12 limitation documented" { // - "e_low_level_lambda - List.drop_at on refcounted List(Str)" // - "e_low_level_lambda - List.drop_at on refcounted List(List(Str))" // +// - "e_low_level_lambda - List.sublist on empty list" +// - "e_low_level_lambda - List.sublist on non-empty list" +// - "e_low_level_lambda - List.sublist start out of bounds" +// - "e_low_level_lambda - List.sublist requesting beyond end of list gives you input list" +// // interpreter_style_test.zig: // - "interpreter: match list pattern destructures" // - "interpreter: match list rest binds slice" diff --git a/src/eval/test/low_level_interp_test.zig b/src/eval/test/low_level_interp_test.zig index 6d76fef66c..77e8825ce5 100644 --- a/src/eval/test/low_level_interp_test.zig +++ b/src/eval/test/low_level_interp_test.zig @@ -830,17 +830,54 @@ test "e_low_level_lambda - List.drop_at on refcounted List(List(Str))" { try testing.expectEqual(@as(i128, 4), elt_len_value); } -test "e_low_level_lambda - List.sublist on non-empty list" { +test "e_low_level_lambda - List.sublist on empty list" { const src = - \\x = List.sublist([0, 1, 2, 3, 4], {len: 10, start: 3}) + \\x = List.sublist([], {start: 0, len: 10}) \\len = List.len(x) ; const len_value = try evalModuleAndGetInt(src, 1); - try testing.expectEqual(@as(i128, 2), len_value); + try testing.expectEqual(@as(i128, 0), 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], {start: 1, len: 3}) + \\len = List.len(x) + \\slice_start = List.get(x, 0) + \\slice_end = List.get(x, 2) + ; + + const len_value = try evalModuleAndGetInt(src, 1); + try testing.expectEqual(@as(i128, 3), len_value); + + const head_value = try evalModuleAndGetString(src, 2, test_allocator); + defer test_allocator.free(head_value); + try testing.expectEqualStrings("Ok(1)", head_value); + + const tail_value = try evalModuleAndGetString(src, 3, test_allocator); + defer test_allocator.free(tail_value); + try testing.expectEqualStrings("Ok(3)", tail_value); +} + +test "e_low_level_lambda - List.sublist start out of bounds" { + const src = + \\x = List.sublist([0, 1, 2, 3, 4], {start: 100, len: 3}) + \\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.sublist requesting beyond end of list gives you input list" { + const src = + \\x = List.sublist([0, 1, 2, 3, 4], {start: 0, len: 10000}) + \\len = List.len(x) + ; + + const len_value = try evalModuleAndGetInt(src, 1); + try testing.expectEqual(@as(i128, 5), len_value); } test "e_low_level_lambda - Dec.to_str returns string representation of decimal" {