From 004219d4eef5123721c90a0ff4a8d9029f238eed Mon Sep 17 00:00:00 2001 From: Richard Feldman Date: Fri, 7 Nov 2025 08:23:06 -0500 Subject: [PATCH] wip --- src/build/builtin_compiler/main.zig | 6 ++++++ src/build/roc/Builtin.roc | 2 -- src/builtins/list.zig | 10 +++++++++ src/canonicalize/Expression.zig | 4 ++++ src/eval/interpreter.zig | 32 +++++++++++++++++++++++++++++ 5 files changed, 52 insertions(+), 2 deletions(-) diff --git a/src/build/builtin_compiler/main.zig b/src/build/builtin_compiler/main.zig index 03bb18df6b..0ae34c46fe 100644 --- a/src/build/builtin_compiler/main.zig +++ b/src/build/builtin_compiler/main.zig @@ -149,6 +149,12 @@ fn replaceStrIsEmptyWithLowLevel(env: *ModuleEnv) !std.ArrayList(CIR.Def.Idx) { if (env.common.findIdent("Builtin.Str.is_empty")) |str_is_empty_ident| { try low_level_map.put(str_is_empty_ident, .str_is_empty); } + if (env.common.findIdent("Builtin.List.len")) |list_len_ident| { + try low_level_map.put(list_len_ident, .list_len); + } + if (env.common.findIdent("Builtin.List.is_empty")) |list_is_empty_ident| { + try low_level_map.put(list_is_empty_ident, .list_is_empty); + } if (env.common.findIdent("Builtin.Set.is_empty")) |set_is_empty_ident| { try low_level_map.put(set_is_empty_ident, .set_is_empty); } diff --git a/src/build/roc/Builtin.roc b/src/build/roc/Builtin.roc index feb433ccf7..dae6f06fd1 100644 --- a/src/build/roc/Builtin.roc +++ b/src/build/roc/Builtin.roc @@ -8,10 +8,8 @@ Builtin := [].{ List := [ProvidedByCompiler].{ len : List(a) -> U64 - len = |_| 0 is_empty : List(a) -> Bool - is_empty = |_| True first : List(a) -> Try(a, [ListWasEmpty]) first = |_| Err(ListWasEmpty) diff --git a/src/builtins/list.zig b/src/builtins/list.zig index ce32f60886..e9147642d7 100644 --- a/src/builtins/list.zig +++ b/src/builtins/list.zig @@ -375,6 +375,16 @@ pub fn listIncref(list: RocList, amount: isize, elements_refcounted: bool) callc list.incref(amount, elements_refcounted); } +/// Get the number of elements in the list. +pub fn listLen(list: RocList) callconv(.c) usize { + return list.len(); +} + +/// Check if the list is empty. +pub fn listIsEmpty(list: RocList) callconv(.c) bool { + return list.isEmpty(); +} + /// Decrement reference count and deallocate when no longer shared. pub fn listDecref( list: RocList, diff --git a/src/canonicalize/Expression.zig b/src/canonicalize/Expression.zig index 3229d1ad7f..a34e08c501 100644 --- a/src/canonicalize/Expression.zig +++ b/src/canonicalize/Expression.zig @@ -387,6 +387,10 @@ pub const Expr = union(enum) { // String operations str_is_empty, + // List operations + list_len, + list_is_empty, + // Set operations set_is_empty, diff --git a/src/eval/interpreter.zig b/src/eval/interpreter.zig index 56fa5a9d9b..3499748205 100644 --- a/src/eval/interpreter.zig +++ b/src/eval/interpreter.zig @@ -2119,6 +2119,38 @@ pub const Interpreter = struct { return try self.makeSimpleBoolValue(result); }, + .list_len => { + // List.len : List(a) -> U64 + // Note: listLen returns usize, but List.len always returns U64. + // We need to cast usize -> u64 for 32-bit targets (e.g. wasm32). + if (args.len != 1) return error.TypeMismatch; + + const list_arg = args[0]; + if (list_arg.ptr == null) return error.TypeMismatch; + + const roc_list: *const builtins.list.RocList = @ptrCast(@alignCast(list_arg.ptr.?)); + const len_usize = builtins.list.listLen(roc_list.*); + const len_u64: u64 = @intCast(len_usize); + + const result_layout = layout.Layout.int(.u64); + var out = try self.pushRaw(result_layout, 0); + out.is_initialized = false; + out.setInt(@intCast(len_u64)); + out.is_initialized = true; + return out; + }, + .list_is_empty => { + // List.is_empty : List(a) -> Bool + if (args.len != 1) return error.TypeMismatch; + + const list_arg = args[0]; + if (list_arg.ptr == null) return error.TypeMismatch; + + const roc_list: *const builtins.list.RocList = @ptrCast(@alignCast(list_arg.ptr.?)); + const result = builtins.list.listIsEmpty(roc_list.*); + + return try self.makeSimpleBoolValue(result); + }, .set_is_empty => { // TODO: implement Set.is_empty self.triggerCrash("Set.is_empty not yet implemented", false, roc_ops);