mirror of
https://github.com/roc-lang/roc.git
synced 2025-08-04 20:28:02 +00:00
List.sortWith and friends
This commit is contained in:
parent
315e9871c1
commit
520bac2905
4 changed files with 235 additions and 21 deletions
|
@ -2005,14 +2005,27 @@ impl<
|
|||
.get_mut(&self.env.module_id)
|
||||
.unwrap();
|
||||
|
||||
let caller_proc = CallerProc::new(
|
||||
self.env.arena,
|
||||
self.env.module_id,
|
||||
ident_ids,
|
||||
self.layout_interner,
|
||||
&higher_order.passed_function,
|
||||
higher_order.closure_env_layout,
|
||||
);
|
||||
let caller_proc = match higher_order.op {
|
||||
HigherOrder::ListMap { .. }
|
||||
| HigherOrder::ListMap2 { .. }
|
||||
| HigherOrder::ListMap3 { .. }
|
||||
| HigherOrder::ListMap4 { .. } => CallerProc::new_list_map(
|
||||
self.env.arena,
|
||||
self.env.module_id,
|
||||
ident_ids,
|
||||
self.layout_interner,
|
||||
&higher_order.passed_function,
|
||||
higher_order.closure_env_layout,
|
||||
),
|
||||
HigherOrder::ListSortWith { .. } => CallerProc::new_compare(
|
||||
self.env.arena,
|
||||
self.env.module_id,
|
||||
ident_ids,
|
||||
self.layout_interner,
|
||||
&higher_order.passed_function,
|
||||
higher_order.closure_env_layout,
|
||||
),
|
||||
};
|
||||
|
||||
let caller = self.debug_symbol("caller");
|
||||
let caller_string = self.lambda_name_to_string(
|
||||
|
@ -2025,7 +2038,7 @@ impl<
|
|||
self.caller_procs.push(caller_proc);
|
||||
|
||||
let argument_layouts = match higher_order.closure_env_layout {
|
||||
None => &higher_order.passed_function.argument_layouts,
|
||||
None => higher_order.passed_function.argument_layouts,
|
||||
Some(_) => &higher_order.passed_function.argument_layouts[1..],
|
||||
};
|
||||
|
||||
|
@ -2445,7 +2458,71 @@ impl<
|
|||
self.free_symbol(&Symbol::DEV_TMP);
|
||||
self.free_symbol(&Symbol::DEV_TMP2);
|
||||
}
|
||||
HigherOrder::ListSortWith { xs } => todo!(),
|
||||
HigherOrder::ListSortWith { xs } => {
|
||||
let element_layout = argument_layouts[0];
|
||||
|
||||
let input_list_layout = LayoutRepr::Builtin(Builtin::List(element_layout));
|
||||
let input_list_in_layout = self
|
||||
.layout_interner
|
||||
.insert_direct_no_semantic(input_list_layout);
|
||||
|
||||
let alignment = self.debug_symbol("alignment");
|
||||
let element_width = self.debug_symbol("old_element_width");
|
||||
|
||||
self.load_layout_alignment(element_layout, alignment);
|
||||
self.load_layout_stack_size(element_layout, element_width);
|
||||
|
||||
self.build_fn_pointer(&caller, caller_string);
|
||||
|
||||
// we pass a null pointer when the data is not owned. the zig code must not call this!
|
||||
let data_is_owned = higher_order.closure_env_layout.is_some()
|
||||
&& higher_order.passed_function.owns_captured_environment;
|
||||
|
||||
self.load_literal(
|
||||
&Symbol::DEV_TMP2,
|
||||
&Layout::BOOL,
|
||||
&Literal::Bool(data_is_owned),
|
||||
);
|
||||
|
||||
// input: RocList,
|
||||
// caller: CompareFn,
|
||||
// data: Opaque,
|
||||
// inc_n_data: IncN,
|
||||
// data_is_owned: bool,
|
||||
// alignment: u32,
|
||||
// element_width: usize,
|
||||
|
||||
let arguments = [
|
||||
xs,
|
||||
caller,
|
||||
data,
|
||||
inc_n_data,
|
||||
Symbol::DEV_TMP2,
|
||||
alignment,
|
||||
element_width,
|
||||
];
|
||||
|
||||
let layouts = [
|
||||
input_list_in_layout,
|
||||
ptr,
|
||||
ptr,
|
||||
ptr,
|
||||
Layout::BOOL,
|
||||
Layout::U32,
|
||||
usize_,
|
||||
];
|
||||
|
||||
self.build_fn_call_stack_return(
|
||||
bitcode::LIST_SORT_WITH.to_string(),
|
||||
&arguments,
|
||||
&layouts,
|
||||
ret_layout,
|
||||
*dst,
|
||||
);
|
||||
|
||||
self.free_symbol(&Symbol::DEV_TMP);
|
||||
self.free_symbol(&Symbol::DEV_TMP2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -660,7 +660,7 @@ impl<'a> CallerProc<'a> {
|
|||
Self::create_symbol(home, ident_ids, &debug_name)
|
||||
}
|
||||
|
||||
pub fn new(
|
||||
pub fn new_list_map(
|
||||
arena: &'a Bump,
|
||||
home: ModuleId,
|
||||
ident_ids: &mut IdentIds,
|
||||
|
@ -672,7 +672,7 @@ impl<'a> CallerProc<'a> {
|
|||
const ARG_SYMBOLS: &[Symbol] = &[ARG_1, ARG_2, ARG_3, ARG_4, ARG_5, ARG_6];
|
||||
|
||||
let argument_layouts = match capture_layout {
|
||||
None => &passed_function.argument_layouts,
|
||||
None => passed_function.argument_layouts,
|
||||
Some(_) => &passed_function.argument_layouts[1..],
|
||||
};
|
||||
|
||||
|
@ -824,6 +824,148 @@ impl<'a> CallerProc<'a> {
|
|||
proc,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_compare(
|
||||
arena: &'a Bump,
|
||||
home: ModuleId,
|
||||
ident_ids: &mut IdentIds,
|
||||
layout_interner: &mut STLayoutInterner<'a>,
|
||||
passed_function: &PassedFunction<'a>,
|
||||
capture_layout: Option<InLayout<'a>>,
|
||||
) -> Self {
|
||||
const ARG_SYMBOLS: &[Symbol] = &[ARG_1, ARG_2, ARG_3];
|
||||
|
||||
let argument_layouts = match capture_layout {
|
||||
None => passed_function.argument_layouts,
|
||||
Some(_) => &passed_function.argument_layouts[1..],
|
||||
};
|
||||
|
||||
let capture_symbol = ARG_SYMBOLS[0];
|
||||
|
||||
let mut ctx = Context {
|
||||
new_linker_data: Vec::new_in(arena),
|
||||
recursive_union: None,
|
||||
op: HelperOp::Eq,
|
||||
};
|
||||
|
||||
let ptr_capture_layout = if let Some(capture_layout) = capture_layout {
|
||||
layout_interner.insert_direct_no_semantic(LayoutRepr::Ptr(capture_layout))
|
||||
} else {
|
||||
layout_interner.insert_direct_no_semantic(LayoutRepr::Ptr(Layout::UNIT))
|
||||
};
|
||||
|
||||
let it = argument_layouts
|
||||
.iter()
|
||||
.map(|l| layout_interner.insert_direct_no_semantic(LayoutRepr::Ptr(*l)));
|
||||
let ptr_argument_layouts = Vec::from_iter_in(it, arena);
|
||||
|
||||
let mut arguments = Vec::with_capacity_in(1 + ptr_argument_layouts.len(), arena);
|
||||
arguments.push(ptr_capture_layout);
|
||||
arguments.extend(ptr_argument_layouts.iter().copied());
|
||||
|
||||
let proc_layout = ProcLayout {
|
||||
arguments: arguments.into_bump_slice(),
|
||||
result: Layout::UNIT,
|
||||
niche: Niche::NONE,
|
||||
};
|
||||
|
||||
let proc_symbol = Self::create_caller_proc_symbol(
|
||||
home,
|
||||
ident_ids,
|
||||
"compare",
|
||||
passed_function.name.name(),
|
||||
);
|
||||
|
||||
ctx.new_linker_data.push((proc_symbol, proc_layout));
|
||||
|
||||
let load_capture = Expr::ptr_load(arena.alloc(capture_symbol));
|
||||
|
||||
let loaded_capture = Self::create_symbol(home, ident_ids, "loaded_capture");
|
||||
let call_result = Self::create_symbol(home, ident_ids, "call_result");
|
||||
|
||||
let loaded_arguments = Vec::from_iter_in(
|
||||
(0..argument_layouts.len())
|
||||
.map(|i| Self::create_symbol(home, ident_ids, &format!("loaded_argument_{i}"))),
|
||||
arena,
|
||||
);
|
||||
|
||||
let mut arguments = loaded_arguments.clone();
|
||||
if capture_layout.is_some() {
|
||||
arguments.push(loaded_capture);
|
||||
}
|
||||
|
||||
let call = Expr::Call(Call {
|
||||
call_type: CallType::ByName {
|
||||
name: passed_function.name,
|
||||
ret_layout: passed_function.return_layout,
|
||||
arg_layouts: passed_function.argument_layouts,
|
||||
specialization_id: passed_function.specialization_id,
|
||||
},
|
||||
arguments: arguments.into_bump_slice(),
|
||||
});
|
||||
|
||||
let mut body = Stmt::Let(
|
||||
call_result,
|
||||
call,
|
||||
passed_function.return_layout,
|
||||
arena.alloc(Stmt::Ret(call_result)),
|
||||
);
|
||||
|
||||
let it = loaded_arguments
|
||||
.iter()
|
||||
.zip(ARG_SYMBOLS.iter().skip(1))
|
||||
.zip(argument_layouts.iter())
|
||||
.rev();
|
||||
|
||||
for ((loaded_argument, load_argument), argument_layout) in it {
|
||||
let load_argument = Expr::ptr_load(arena.alloc(load_argument));
|
||||
|
||||
body = Stmt::Let(
|
||||
*loaded_argument,
|
||||
load_argument,
|
||||
*argument_layout,
|
||||
arena.alloc(body),
|
||||
);
|
||||
}
|
||||
|
||||
if let Some(capture_layout) = capture_layout {
|
||||
body = Stmt::Let(
|
||||
loaded_capture,
|
||||
load_capture,
|
||||
capture_layout,
|
||||
arena.alloc(body),
|
||||
);
|
||||
}
|
||||
|
||||
let mut arg_symbols = ARG_SYMBOLS.iter();
|
||||
let mut args = Vec::with_capacity_in(1 + ptr_argument_layouts.len(), arena);
|
||||
|
||||
args.push((ptr_capture_layout, *arg_symbols.next().unwrap()));
|
||||
for l in &ptr_argument_layouts {
|
||||
args.push((*l, *arg_symbols.next().unwrap()));
|
||||
}
|
||||
|
||||
let proc = Proc {
|
||||
name: LambdaName::no_niche(proc_symbol),
|
||||
args: args.into_bump_slice(),
|
||||
body,
|
||||
closure_data_layout: None,
|
||||
ret_layout: Layout::BOOL,
|
||||
is_self_recursive: SelfRecursive::NotSelfRecursive,
|
||||
is_erased: false,
|
||||
};
|
||||
|
||||
if true {
|
||||
home.register_debug_idents(ident_ids);
|
||||
println!("{}", proc.to_pretty(layout_interner, 200, true));
|
||||
}
|
||||
|
||||
Self {
|
||||
proc_symbol,
|
||||
proc_layout,
|
||||
proc,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn let_lowlevel<'a>(
|
||||
|
|
|
@ -2909,7 +2909,7 @@ fn cleanup_because_exception() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm", feature = "gen-dev"))]
|
||||
fn list_sort_with() {
|
||||
assert_evals_to!(
|
||||
"List.sortWith [] Num.compare",
|
||||
|
@ -2929,7 +2929,7 @@ fn list_sort_with() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm", feature = "gen-dev"))]
|
||||
fn list_sort_asc() {
|
||||
assert_evals_to!(
|
||||
"List.sortAsc []",
|
||||
|
@ -2944,7 +2944,7 @@ fn list_sort_asc() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm", feature = "gen-dev"))]
|
||||
fn list_sort_desc() {
|
||||
assert_evals_to!(
|
||||
"List.sortDesc []",
|
||||
|
|
|
@ -3,9 +3,4 @@ app "rocLovesZig"
|
|||
imports []
|
||||
provides [main] to pf
|
||||
|
||||
main =
|
||||
f = (\a,b -> Pair a b)
|
||||
l = List.map2 [1,2,3] [3,2,1] f
|
||||
|
||||
when List.len l is
|
||||
_ -> "Roc <3 Zig!\n"
|
||||
main = "Roc <3 Zig!\n"
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue