mirror of
https://github.com/roc-lang/roc.git
synced 2025-07-24 06:55:15 +00:00
List.appendUnsafe and List.reserve
This commit is contained in:
parent
dda79a255e
commit
56c9787e8f
13 changed files with 165 additions and 81 deletions
|
@ -1029,7 +1029,7 @@ fn lowlevel_spec(
|
||||||
|
|
||||||
with_new_heap_cell(builder, block, bag)
|
with_new_heap_cell(builder, block, bag)
|
||||||
}
|
}
|
||||||
ListAppend => {
|
ListAppendUnsafe => {
|
||||||
let list = env.symbols[&arguments[0]];
|
let list = env.symbols[&arguments[0]];
|
||||||
let to_insert = env.symbols[&arguments[1]];
|
let to_insert = env.symbols[&arguments[1]];
|
||||||
|
|
||||||
|
|
|
@ -404,21 +404,41 @@ pub fn listMap4(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn listWithCapacity(capacity: usize, alignment: u32, element_width: usize) callconv(.C) RocList {
|
pub fn listWithCapacity(
|
||||||
|
capacity: usize,
|
||||||
|
alignment: u32,
|
||||||
|
element_width: usize,
|
||||||
|
) callconv(.C) RocList {
|
||||||
var output = RocList.allocate(alignment, capacity, element_width);
|
var output = RocList.allocate(alignment, capacity, element_width);
|
||||||
output.length = 0;
|
output.length = 0;
|
||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn listAppend(list: RocList, alignment: u32, element: Opaque, element_width: usize, update_mode: UpdateMode) callconv(.C) RocList {
|
pub fn listReserve(
|
||||||
|
list: RocList,
|
||||||
|
alignment: u32,
|
||||||
|
spare: usize,
|
||||||
|
element_width: usize,
|
||||||
|
update_mode: UpdateMode,
|
||||||
|
) callconv(.C) RocList {
|
||||||
const old_length = list.len();
|
const old_length = list.len();
|
||||||
var output: RocList = undefined;
|
if ((update_mode == .InPlace or list.isUnique()) and list.capacity >= list.len() + spare) {
|
||||||
if (update_mode == .InPlace and list.capacity >= old_length + 1) {
|
return list;
|
||||||
output = list;
|
|
||||||
output.length += 1;
|
|
||||||
} else {
|
} else {
|
||||||
output = list.reallocate(alignment, old_length + 1, element_width);
|
var output = list.reallocate(alignment, old_length + spare, element_width);
|
||||||
|
output.length = old_length;
|
||||||
|
return output;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn listAppendUnsafe(
|
||||||
|
list: RocList,
|
||||||
|
element: Opaque,
|
||||||
|
element_width: usize,
|
||||||
|
) callconv(.C) RocList {
|
||||||
|
const old_length = list.len();
|
||||||
|
var output = list;
|
||||||
|
output.length += 1;
|
||||||
|
|
||||||
if (output.bytes) |target| {
|
if (output.bytes) |target| {
|
||||||
if (element) |source| {
|
if (element) |source| {
|
||||||
|
@ -429,6 +449,11 @@ pub fn listAppend(list: RocList, alignment: u32, element: Opaque, element_width:
|
||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn listAppend(list: RocList, alignment: u32, element: Opaque, element_width: usize, update_mode: UpdateMode) callconv(.C) RocList {
|
||||||
|
const with_capacity = listReserve(list, alignment, 1, element_width, update_mode);
|
||||||
|
return listAppendUnsafe(with_capacity, element, element_width);
|
||||||
|
}
|
||||||
|
|
||||||
pub fn listPrepend(list: RocList, alignment: u32, element: Opaque, element_width: usize) callconv(.C) RocList {
|
pub fn listPrepend(list: RocList, alignment: u32, element: Opaque, element_width: usize) callconv(.C) RocList {
|
||||||
const old_length = list.len();
|
const old_length = list.len();
|
||||||
var output = list.reallocate(alignment, old_length + 1, element_width);
|
var output = list.reallocate(alignment, old_length + 1, element_width);
|
||||||
|
|
|
@ -40,7 +40,8 @@ comptime {
|
||||||
exportListFn(list.listMap2, "map2");
|
exportListFn(list.listMap2, "map2");
|
||||||
exportListFn(list.listMap3, "map3");
|
exportListFn(list.listMap3, "map3");
|
||||||
exportListFn(list.listMap4, "map4");
|
exportListFn(list.listMap4, "map4");
|
||||||
exportListFn(list.listAppend, "append");
|
exportListFn(list.listAppendUnsafe, "append_unsafe");
|
||||||
|
exportListFn(list.listReserve, "reserve");
|
||||||
exportListFn(list.listPrepend, "prepend");
|
exportListFn(list.listPrepend, "prepend");
|
||||||
exportListFn(list.listWithCapacity, "with_capacity");
|
exportListFn(list.listWithCapacity, "with_capacity");
|
||||||
exportListFn(list.listSortWith, "sort_with");
|
exportListFn(list.listSortWith, "sort_with");
|
||||||
|
|
|
@ -52,6 +52,7 @@ interface List
|
||||||
dropIf,
|
dropIf,
|
||||||
sortAsc,
|
sortAsc,
|
||||||
sortDesc,
|
sortDesc,
|
||||||
|
reserve,
|
||||||
]
|
]
|
||||||
imports [
|
imports [
|
||||||
Bool.{ Bool },
|
Bool.{ Bool },
|
||||||
|
@ -243,6 +244,17 @@ set = \list, index, value ->
|
||||||
## >>> [0, 1, 2]
|
## >>> [0, 1, 2]
|
||||||
## >>> |> List.append 3
|
## >>> |> List.append 3
|
||||||
append : List a, a -> List a
|
append : List a, a -> List a
|
||||||
|
append = \list, element ->
|
||||||
|
list
|
||||||
|
|> List.reserve 1
|
||||||
|
|> List.appendUnsafe element
|
||||||
|
|
||||||
|
## Writes the element after the current last element unconditionally.
|
||||||
|
## In other words, it is assumed that
|
||||||
|
##
|
||||||
|
## - the list is owned (i.e. can be updated in-place
|
||||||
|
## - the list has at least one element of spare capacity
|
||||||
|
appendUnsafe : List a, a -> List a
|
||||||
|
|
||||||
## Add a single element to the beginning of a list.
|
## Add a single element to the beginning of a list.
|
||||||
##
|
##
|
||||||
|
@ -262,6 +274,9 @@ len : List a -> Nat
|
||||||
## Create a list with space for at least capacity elements
|
## Create a list with space for at least capacity elements
|
||||||
withCapacity : Nat -> List a
|
withCapacity : Nat -> List a
|
||||||
|
|
||||||
|
## Enlarge the list for at least capacity additional elements
|
||||||
|
reserve : List a, Nat -> List a
|
||||||
|
|
||||||
## Put two lists together.
|
## Put two lists together.
|
||||||
##
|
##
|
||||||
## >>> List.concat [1, 2, 3] [4, 5]
|
## >>> List.concat [1, 2, 3] [4, 5]
|
||||||
|
|
|
@ -359,8 +359,6 @@ pub const LIST_MAP: &str = "roc_builtins.list.map";
|
||||||
pub const LIST_MAP2: &str = "roc_builtins.list.map2";
|
pub const LIST_MAP2: &str = "roc_builtins.list.map2";
|
||||||
pub const LIST_MAP3: &str = "roc_builtins.list.map3";
|
pub const LIST_MAP3: &str = "roc_builtins.list.map3";
|
||||||
pub const LIST_MAP4: &str = "roc_builtins.list.map4";
|
pub const LIST_MAP4: &str = "roc_builtins.list.map4";
|
||||||
pub const LIST_APPEND: &str = "roc_builtins.list.append";
|
|
||||||
pub const LIST_PREPEND: &str = "roc_builtins.list.prepend";
|
|
||||||
pub const LIST_SUBLIST: &str = "roc_builtins.list.sublist";
|
pub const LIST_SUBLIST: &str = "roc_builtins.list.sublist";
|
||||||
pub const LIST_DROP_AT: &str = "roc_builtins.list.drop_at";
|
pub const LIST_DROP_AT: &str = "roc_builtins.list.drop_at";
|
||||||
pub const LIST_SWAP: &str = "roc_builtins.list.swap";
|
pub const LIST_SWAP: &str = "roc_builtins.list.swap";
|
||||||
|
@ -370,6 +368,9 @@ pub const LIST_CONCAT: &str = "roc_builtins.list.concat";
|
||||||
pub const LIST_REPLACE: &str = "roc_builtins.list.replace";
|
pub const LIST_REPLACE: &str = "roc_builtins.list.replace";
|
||||||
pub const LIST_REPLACE_IN_PLACE: &str = "roc_builtins.list.replace_in_place";
|
pub const LIST_REPLACE_IN_PLACE: &str = "roc_builtins.list.replace_in_place";
|
||||||
pub const LIST_IS_UNIQUE: &str = "roc_builtins.list.is_unique";
|
pub const LIST_IS_UNIQUE: &str = "roc_builtins.list.is_unique";
|
||||||
|
pub const LIST_PREPEND: &str = "roc_builtins.list.prepend";
|
||||||
|
pub const LIST_APPEND_UNSAFE: &str = "roc_builtins.list.append_unsafe";
|
||||||
|
pub const LIST_RESERVE: &str = "roc_builtins.list.reserve";
|
||||||
|
|
||||||
pub const DEC_FROM_STR: &str = "roc_builtins.dec.from_str";
|
pub const DEC_FROM_STR: &str = "roc_builtins.dec.from_str";
|
||||||
pub const DEC_FROM_F64: &str = "roc_builtins.dec.from_f64";
|
pub const DEC_FROM_F64: &str = "roc_builtins.dec.from_f64";
|
||||||
|
|
|
@ -110,9 +110,10 @@ pub fn builtin_defs_map(symbol: Symbol, var_store: &mut VarStore) -> Option<Def>
|
||||||
LIST_UNREACHABLE => roc_unreachable,
|
LIST_UNREACHABLE => roc_unreachable,
|
||||||
LIST_LEN => list_len,
|
LIST_LEN => list_len,
|
||||||
LIST_WITH_CAPACITY => list_with_capacity,
|
LIST_WITH_CAPACITY => list_with_capacity,
|
||||||
|
LIST_RESERVE => list_reserve,
|
||||||
|
LIST_APPEND_UNSAFE => list_append_unsafe,
|
||||||
LIST_GET_UNSAFE => list_get_unsafe,
|
LIST_GET_UNSAFE => list_get_unsafe,
|
||||||
LIST_REPLACE_UNSAFE => list_replace_unsafe,
|
LIST_REPLACE_UNSAFE => list_replace_unsafe,
|
||||||
LIST_APPEND => list_append,
|
|
||||||
LIST_IS_EMPTY => list_is_empty,
|
LIST_IS_EMPTY => list_is_empty,
|
||||||
LIST_CONCAT => list_concat,
|
LIST_CONCAT => list_concat,
|
||||||
LIST_PREPEND => list_prepend,
|
LIST_PREPEND => list_prepend,
|
||||||
|
@ -2069,6 +2070,14 @@ fn list_with_capacity(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||||
lowlevel_1(symbol, LowLevel::ListWithCapacity, var_store)
|
lowlevel_1(symbol, LowLevel::ListWithCapacity, var_store)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn list_reserve(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||||
|
lowlevel_2(symbol, LowLevel::ListReserve, var_store)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn list_append_unsafe(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||||
|
lowlevel_2(symbol, LowLevel::ListAppendUnsafe, var_store)
|
||||||
|
}
|
||||||
|
|
||||||
/// List.getUnsafe : List elem, Int -> elem
|
/// List.getUnsafe : List elem, Int -> elem
|
||||||
fn list_get_unsafe(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
fn list_get_unsafe(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||||
lowlevel_2(symbol, LowLevel::ListGetUnsafe, var_store)
|
lowlevel_2(symbol, LowLevel::ListGetUnsafe, var_store)
|
||||||
|
@ -2314,50 +2323,9 @@ fn list_drop_at(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||||
lowlevel_2(symbol, LowLevel::ListDropAt, var_store)
|
lowlevel_2(symbol, LowLevel::ListDropAt, var_store)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// List.append : List elem, elem -> List elem
|
|
||||||
fn list_append(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
|
||||||
let list_var = var_store.fresh();
|
|
||||||
let elem_var = var_store.fresh();
|
|
||||||
|
|
||||||
let body = RunLowLevel {
|
|
||||||
op: LowLevel::ListAppend,
|
|
||||||
args: vec![
|
|
||||||
(list_var, Var(Symbol::ARG_1)),
|
|
||||||
(elem_var, Var(Symbol::ARG_2)),
|
|
||||||
],
|
|
||||||
ret_var: list_var,
|
|
||||||
};
|
|
||||||
|
|
||||||
defn(
|
|
||||||
symbol,
|
|
||||||
vec![(list_var, Symbol::ARG_1), (elem_var, Symbol::ARG_2)],
|
|
||||||
var_store,
|
|
||||||
body,
|
|
||||||
list_var,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// List.prepend : List elem, elem -> List elem
|
/// List.prepend : List elem, elem -> List elem
|
||||||
fn list_prepend(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
fn list_prepend(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||||
let list_var = var_store.fresh();
|
lowlevel_2(symbol, LowLevel::ListPrepend, var_store)
|
||||||
let elem_var = var_store.fresh();
|
|
||||||
|
|
||||||
let body = RunLowLevel {
|
|
||||||
op: LowLevel::ListPrepend,
|
|
||||||
args: vec![
|
|
||||||
(list_var, Var(Symbol::ARG_1)),
|
|
||||||
(elem_var, Var(Symbol::ARG_2)),
|
|
||||||
],
|
|
||||||
ret_var: list_var,
|
|
||||||
};
|
|
||||||
|
|
||||||
defn(
|
|
||||||
symbol,
|
|
||||||
vec![(list_var, Symbol::ARG_1), (elem_var, Symbol::ARG_2)],
|
|
||||||
var_store,
|
|
||||||
body,
|
|
||||||
list_var,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// List.unreachable : [] -> a
|
/// List.unreachable : [] -> a
|
||||||
|
|
|
@ -8,10 +8,10 @@ use crate::llvm::build_dict::{
|
||||||
};
|
};
|
||||||
use crate::llvm::build_hash::generic_hash;
|
use crate::llvm::build_hash::generic_hash;
|
||||||
use crate::llvm::build_list::{
|
use crate::llvm::build_list::{
|
||||||
self, allocate_list, empty_polymorphic_list, list_append, list_concat, list_drop_at,
|
self, allocate_list, empty_polymorphic_list, list_append_unsafe, list_concat, list_drop_at,
|
||||||
list_get_unsafe, list_len, list_map, list_map2, list_map3, list_map4, list_prepend,
|
list_get_unsafe, list_len, list_map, list_map2, list_map3, list_map4, list_prepend,
|
||||||
list_replace_unsafe, list_sort_with, list_sublist, list_swap, list_symbol_to_c_abi,
|
list_replace_unsafe, list_reserve, list_sort_with, list_sublist, list_swap,
|
||||||
list_to_c_abi, list_with_capacity,
|
list_symbol_to_c_abi, list_to_c_abi, list_with_capacity,
|
||||||
};
|
};
|
||||||
use crate::llvm::build_str::{str_from_float, str_from_int, str_from_utf8, str_from_utf8_range};
|
use crate::llvm::build_str::{str_from_float, str_from_int, str_from_utf8, str_from_utf8_range};
|
||||||
use crate::llvm::compare::{generic_eq, generic_neq};
|
use crate::llvm::compare::{generic_eq, generic_neq};
|
||||||
|
@ -5531,14 +5531,24 @@ fn run_low_level<'a, 'ctx, 'env>(
|
||||||
|
|
||||||
list_concat(env, first_list, second_list, element_layout)
|
list_concat(env, first_list, second_list, element_layout)
|
||||||
}
|
}
|
||||||
ListAppend => {
|
ListAppendUnsafe => {
|
||||||
// List.append : List elem, elem -> List elem
|
// List.appendUnsafe : List elem, elem -> List elem
|
||||||
debug_assert_eq!(args.len(), 2);
|
debug_assert_eq!(args.len(), 2);
|
||||||
|
|
||||||
let original_wrapper = load_symbol(scope, &args[0]).into_struct_value();
|
let original_wrapper = load_symbol(scope, &args[0]).into_struct_value();
|
||||||
let (elem, elem_layout) = load_symbol_and_layout(scope, &args[1]);
|
let (elem, elem_layout) = load_symbol_and_layout(scope, &args[1]);
|
||||||
|
|
||||||
list_append(env, original_wrapper, elem, elem_layout, update_mode)
|
list_append_unsafe(env, original_wrapper, elem, elem_layout)
|
||||||
|
}
|
||||||
|
ListReserve => {
|
||||||
|
// List.reserve : List elem, Nat -> List elem
|
||||||
|
debug_assert_eq!(args.len(), 2);
|
||||||
|
|
||||||
|
let (list, list_layout) = load_symbol_and_layout(scope, &args[0]);
|
||||||
|
let element_layout = list_element_layout!(list_layout);
|
||||||
|
let spare = load_symbol(scope, &args[1]);
|
||||||
|
|
||||||
|
list_reserve(env, list, spare, element_layout, update_mode)
|
||||||
}
|
}
|
||||||
ListSwap => {
|
ListSwap => {
|
||||||
// List.swap : List elem, Nat, Nat -> List elem
|
// List.swap : List elem, Nat, Nat -> List elem
|
||||||
|
|
|
@ -146,24 +146,42 @@ pub fn list_get_unsafe<'a, 'ctx, 'env>(
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
/// List.append : List elem, elem -> List elem
|
/// List.reserve : List elem, Nat -> List elem
|
||||||
pub fn list_append<'a, 'ctx, 'env>(
|
pub fn list_reserve<'a, 'ctx, 'env>(
|
||||||
env: &Env<'a, 'ctx, 'env>,
|
env: &Env<'a, 'ctx, 'env>,
|
||||||
original_wrapper: StructValue<'ctx>,
|
list: BasicValueEnum<'ctx>,
|
||||||
element: BasicValueEnum<'ctx>,
|
spare: BasicValueEnum<'ctx>,
|
||||||
element_layout: &Layout<'a>,
|
element_layout: &Layout<'a>,
|
||||||
update_mode: UpdateMode,
|
update_mode: UpdateMode,
|
||||||
) -> BasicValueEnum<'ctx> {
|
) -> BasicValueEnum<'ctx> {
|
||||||
call_list_bitcode_fn(
|
call_list_bitcode_fn(
|
||||||
env,
|
env,
|
||||||
&[
|
&[
|
||||||
list_to_c_abi(env, original_wrapper.into()).into(),
|
list_to_c_abi(env, list).into(),
|
||||||
env.alignment_intvalue(element_layout),
|
env.alignment_intvalue(element_layout),
|
||||||
pass_element_as_opaque(env, element, *element_layout),
|
spare,
|
||||||
layout_width(env, element_layout),
|
layout_width(env, element_layout),
|
||||||
pass_update_mode(env, update_mode),
|
pass_update_mode(env, update_mode),
|
||||||
],
|
],
|
||||||
bitcode::LIST_APPEND,
|
bitcode::LIST_RESERVE,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// List.appendUnsafe : List elem, elem -> List elem
|
||||||
|
pub fn list_append_unsafe<'a, 'ctx, 'env>(
|
||||||
|
env: &Env<'a, 'ctx, 'env>,
|
||||||
|
original_wrapper: StructValue<'ctx>,
|
||||||
|
element: BasicValueEnum<'ctx>,
|
||||||
|
element_layout: &Layout<'a>,
|
||||||
|
) -> BasicValueEnum<'ctx> {
|
||||||
|
call_list_bitcode_fn(
|
||||||
|
env,
|
||||||
|
&[
|
||||||
|
list_to_c_abi(env, original_wrapper.into()).into(),
|
||||||
|
pass_element_as_opaque(env, element, *element_layout),
|
||||||
|
layout_width(env, element_layout),
|
||||||
|
],
|
||||||
|
bitcode::LIST_APPEND_UNSAFE,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -488,22 +488,27 @@ impl<'a> LowLevelCall<'a> {
|
||||||
|
|
||||||
backend.call_host_fn_after_loading_args(bitcode::LIST_CONCAT, 7, false);
|
backend.call_host_fn_after_loading_args(bitcode::LIST_CONCAT, 7, false);
|
||||||
}
|
}
|
||||||
ListAppend => {
|
|
||||||
// List.append : List elem, elem -> List elem
|
ListReserve => {
|
||||||
|
// List.reserve : List elem, Nat -> List elem
|
||||||
|
|
||||||
let list: Symbol = self.arguments[0];
|
let list: Symbol = self.arguments[0];
|
||||||
let elem: Symbol = self.arguments[1];
|
let spare: Symbol = self.arguments[1];
|
||||||
|
|
||||||
let elem_layout = unwrap_list_elem_layout(self.ret_layout);
|
let elem_layout = unwrap_list_elem_layout(self.ret_layout);
|
||||||
let (elem_width, elem_align) = elem_layout.stack_size_and_alignment(TARGET_INFO);
|
let (elem_width, elem_align) = elem_layout.stack_size_and_alignment(TARGET_INFO);
|
||||||
let (elem_local, elem_offset, _) =
|
let (spare_local, spare_offset, _) = ensure_symbol_is_in_memory(
|
||||||
ensure_symbol_is_in_memory(backend, elem, *elem_layout, backend.env.arena);
|
backend,
|
||||||
|
spare,
|
||||||
|
Layout::usize(TARGET_INFO),
|
||||||
|
backend.env.arena,
|
||||||
|
);
|
||||||
|
|
||||||
// Zig arguments Wasm types
|
// Zig arguments Wasm types
|
||||||
// (return pointer) i32
|
// (return pointer) i32
|
||||||
// list: RocList i64, i32
|
// list: RocList i64, i32
|
||||||
// alignment: u32 i32
|
// alignment: u32 i32
|
||||||
// element: Opaque i32
|
// spare: usize i32
|
||||||
// element_width: usize i32
|
// element_width: usize i32
|
||||||
// update_mode: UpdateMode i32
|
// update_mode: UpdateMode i32
|
||||||
|
|
||||||
|
@ -519,6 +524,46 @@ impl<'a> LowLevelCall<'a> {
|
||||||
|
|
||||||
backend.code_builder.i32_const(elem_align as i32);
|
backend.code_builder.i32_const(elem_align as i32);
|
||||||
|
|
||||||
|
backend.code_builder.get_local(spare_local);
|
||||||
|
if spare_offset > 0 {
|
||||||
|
backend.code_builder.i32_const(spare_offset as i32);
|
||||||
|
backend.code_builder.i32_add();
|
||||||
|
}
|
||||||
|
|
||||||
|
backend.code_builder.i32_const(elem_width as i32);
|
||||||
|
|
||||||
|
backend.code_builder.i32_const(UPDATE_MODE_IMMUTABLE);
|
||||||
|
|
||||||
|
backend.call_host_fn_after_loading_args(bitcode::LIST_RESERVE, 7, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
ListAppendUnsafe => {
|
||||||
|
// List.append : List elem, elem -> List elem
|
||||||
|
|
||||||
|
let list: Symbol = self.arguments[0];
|
||||||
|
let elem: Symbol = self.arguments[1];
|
||||||
|
|
||||||
|
let elem_layout = unwrap_list_elem_layout(self.ret_layout);
|
||||||
|
let elem_width = elem_layout.stack_size(TARGET_INFO);
|
||||||
|
let (elem_local, elem_offset, _) =
|
||||||
|
ensure_symbol_is_in_memory(backend, elem, *elem_layout, backend.env.arena);
|
||||||
|
|
||||||
|
// Zig arguments Wasm types
|
||||||
|
// (return pointer) i32
|
||||||
|
// list: RocList i64, i32
|
||||||
|
// element: Opaque i32
|
||||||
|
// element_width: usize i32
|
||||||
|
|
||||||
|
// return pointer and list
|
||||||
|
backend.storage.load_symbols_for_call(
|
||||||
|
backend.env.arena,
|
||||||
|
&mut backend.code_builder,
|
||||||
|
&[list],
|
||||||
|
self.ret_symbol,
|
||||||
|
&WasmLayout::new(&self.ret_layout),
|
||||||
|
CallConv::Zig,
|
||||||
|
);
|
||||||
|
|
||||||
backend.code_builder.get_local(elem_local);
|
backend.code_builder.get_local(elem_local);
|
||||||
if elem_offset > 0 {
|
if elem_offset > 0 {
|
||||||
backend.code_builder.i32_const(elem_offset as i32);
|
backend.code_builder.i32_const(elem_offset as i32);
|
||||||
|
@ -526,9 +571,8 @@ impl<'a> LowLevelCall<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
backend.code_builder.i32_const(elem_width as i32);
|
backend.code_builder.i32_const(elem_width as i32);
|
||||||
backend.code_builder.i32_const(UPDATE_MODE_IMMUTABLE);
|
|
||||||
|
|
||||||
backend.call_host_fn_after_loading_args(bitcode::LIST_APPEND, 7, false);
|
backend.call_host_fn_after_loading_args(bitcode::LIST_APPEND_UNSAFE, 4, false);
|
||||||
}
|
}
|
||||||
ListPrepend => {
|
ListPrepend => {
|
||||||
// List.prepend : List elem, elem -> List elem
|
// List.prepend : List elem, elem -> List elem
|
||||||
|
|
|
@ -32,10 +32,11 @@ pub enum LowLevel {
|
||||||
StrGetScalarUnsafe,
|
StrGetScalarUnsafe,
|
||||||
ListLen,
|
ListLen,
|
||||||
ListWithCapacity,
|
ListWithCapacity,
|
||||||
|
ListReserve,
|
||||||
|
ListAppendUnsafe,
|
||||||
ListGetUnsafe,
|
ListGetUnsafe,
|
||||||
ListReplaceUnsafe,
|
ListReplaceUnsafe,
|
||||||
ListConcat,
|
ListConcat,
|
||||||
ListAppend,
|
|
||||||
ListPrepend,
|
ListPrepend,
|
||||||
ListMap,
|
ListMap,
|
||||||
ListMap2,
|
ListMap2,
|
||||||
|
@ -209,7 +210,7 @@ impl LowLevelWrapperType {
|
||||||
Symbol::LIST_GET => WrapperIsRequired,
|
Symbol::LIST_GET => WrapperIsRequired,
|
||||||
Symbol::LIST_REPLACE => WrapperIsRequired,
|
Symbol::LIST_REPLACE => WrapperIsRequired,
|
||||||
Symbol::LIST_CONCAT => CanBeReplacedBy(ListConcat),
|
Symbol::LIST_CONCAT => CanBeReplacedBy(ListConcat),
|
||||||
Symbol::LIST_APPEND => CanBeReplacedBy(ListAppend),
|
Symbol::LIST_APPEND_UNSAFE => CanBeReplacedBy(ListAppendUnsafe),
|
||||||
Symbol::LIST_PREPEND => CanBeReplacedBy(ListPrepend),
|
Symbol::LIST_PREPEND => CanBeReplacedBy(ListPrepend),
|
||||||
Symbol::LIST_MAP => WrapperIsRequired,
|
Symbol::LIST_MAP => WrapperIsRequired,
|
||||||
Symbol::LIST_MAP2 => WrapperIsRequired,
|
Symbol::LIST_MAP2 => WrapperIsRequired,
|
||||||
|
|
|
@ -1272,6 +1272,8 @@ define_builtins! {
|
||||||
62 LIST_WITH_CAPACITY: "withCapacity"
|
62 LIST_WITH_CAPACITY: "withCapacity"
|
||||||
63 LIST_ITERATE: "iterate"
|
63 LIST_ITERATE: "iterate"
|
||||||
64 LIST_UNREACHABLE: "unreachable"
|
64 LIST_UNREACHABLE: "unreachable"
|
||||||
|
65 LIST_RESERVE: "reserve"
|
||||||
|
66 LIST_APPEND_UNSAFE: "appendUnsafe"
|
||||||
}
|
}
|
||||||
6 RESULT: "Result" => {
|
6 RESULT: "Result" => {
|
||||||
0 RESULT_RESULT: "Result" // the Result.Result type alias
|
0 RESULT_RESULT: "Result" // the Result.Result type alias
|
||||||
|
|
|
@ -910,9 +910,8 @@ pub fn lowlevel_borrow_signature(arena: &Bump, op: LowLevel) -> &[bool] {
|
||||||
ListMap4 => arena.alloc_slice_copy(&[owned, owned, owned, owned, function, closure_data]),
|
ListMap4 => arena.alloc_slice_copy(&[owned, owned, owned, owned, function, closure_data]),
|
||||||
ListSortWith => arena.alloc_slice_copy(&[owned, function, closure_data]),
|
ListSortWith => arena.alloc_slice_copy(&[owned, function, closure_data]),
|
||||||
|
|
||||||
// TODO when we have lists with capacity (if ever)
|
ListAppendUnsafe => arena.alloc_slice_copy(&[owned, owned]),
|
||||||
// List.append should own its first argument
|
ListReserve => arena.alloc_slice_copy(&[owned, irrelevant]),
|
||||||
ListAppend => arena.alloc_slice_copy(&[owned, owned]),
|
|
||||||
ListSublist => arena.alloc_slice_copy(&[owned, irrelevant, irrelevant]),
|
ListSublist => arena.alloc_slice_copy(&[owned, irrelevant, irrelevant]),
|
||||||
ListDropAt => arena.alloc_slice_copy(&[owned, irrelevant]),
|
ListDropAt => arena.alloc_slice_copy(&[owned, irrelevant]),
|
||||||
ListSwap => arena.alloc_slice_copy(&[owned, irrelevant, irrelevant]),
|
ListSwap => arena.alloc_slice_copy(&[owned, irrelevant, irrelevant]),
|
||||||
|
|
|
@ -154,7 +154,7 @@ fn variously_sized_list_literals() {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||||
fn list_append() {
|
fn list_append_basic() {
|
||||||
assert_evals_to!(
|
assert_evals_to!(
|
||||||
"List.append [1] 2",
|
"List.append [1] 2",
|
||||||
RocList::from_slice(&[1, 2]),
|
RocList::from_slice(&[1, 2]),
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue