mirror of
https://github.com/roc-lang/roc.git
synced 2025-10-03 08:34:33 +00:00
Merge remote-tracking branch 'origin/trunk' into list-empty-record
This commit is contained in:
commit
54fb482b79
29 changed files with 968 additions and 1149 deletions
|
@ -178,7 +178,7 @@ mod cli_run {
|
|||
&example_file("benchmarks", "NQueens.roc"),
|
||||
"nqueens",
|
||||
&[],
|
||||
"724\n",
|
||||
"4\n",
|
||||
false,
|
||||
);
|
||||
}
|
||||
|
@ -207,6 +207,30 @@ mod cli_run {
|
|||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[serial(deriv)]
|
||||
fn run_rbtree_insert_not_optimized() {
|
||||
check_output(
|
||||
&example_file("benchmarks", "RBTreeInsert.roc"),
|
||||
"rbtree-insert",
|
||||
&[],
|
||||
"Node Black 0 {} Empty Empty\n",
|
||||
false,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[serial(deriv)]
|
||||
fn run_rbtree_delete_not_optimized() {
|
||||
check_output(
|
||||
&example_file("benchmarks", "RBTreeDel.roc"),
|
||||
"rbtree-del",
|
||||
&[],
|
||||
"30\n",
|
||||
false,
|
||||
);
|
||||
}
|
||||
|
||||
// #[test]
|
||||
// #[serial(effect)]
|
||||
// fn run_effect_unoptimized() {
|
||||
|
|
|
@ -831,20 +831,14 @@ fn strConcatHelp(allocator: *Allocator, comptime T: type, result_in_place: InPla
|
|||
var result = RocStr.initBig(allocator, T, result_in_place, combined_length);
|
||||
|
||||
{
|
||||
const old_if_small = &@bitCast([16]u8, arg1);
|
||||
const old_if_big = @ptrCast([*]u8, arg1.str_bytes);
|
||||
const old_bytes = if (arg1.isSmallStr()) old_if_small else old_if_big;
|
||||
|
||||
const new_bytes: [*]u8 = @ptrCast([*]u8, result.str_bytes);
|
||||
const old_bytes = arg1.asU8ptr();
|
||||
const new_bytes = @ptrCast([*]u8, result.str_bytes);
|
||||
|
||||
@memcpy(new_bytes, old_bytes, arg1.len());
|
||||
}
|
||||
|
||||
{
|
||||
const old_if_small = &@bitCast([16]u8, arg2);
|
||||
const old_if_big = @ptrCast([*]u8, arg2.str_bytes);
|
||||
const old_bytes = if (arg2.isSmallStr()) old_if_small else old_if_big;
|
||||
|
||||
const old_bytes = arg2.asU8ptr();
|
||||
const new_bytes = @ptrCast([*]u8, result.str_bytes) + arg1.len();
|
||||
|
||||
@memcpy(new_bytes, old_bytes, arg2.len());
|
||||
|
|
|
@ -789,8 +789,19 @@ fn canonicalize_pending_def<'a>(
|
|||
|
||||
let arity = typ.arity();
|
||||
|
||||
let problem = match &loc_can_pattern.value {
|
||||
Pattern::Identifier(symbol) => RuntimeError::NoImplementationNamed {
|
||||
def_symbol: *symbol,
|
||||
},
|
||||
Pattern::Shadowed(region, loc_ident) => RuntimeError::Shadowing {
|
||||
original_region: *region,
|
||||
shadow: loc_ident.clone(),
|
||||
},
|
||||
_ => RuntimeError::NoImplementation,
|
||||
};
|
||||
|
||||
// Fabricate a body for this annotation, that will error at runtime
|
||||
let value = Expr::RuntimeError(RuntimeError::NoImplementation);
|
||||
let value = Expr::RuntimeError(problem);
|
||||
let is_closure = arity > 0;
|
||||
let loc_can_expr = if !is_closure {
|
||||
Located {
|
||||
|
|
|
@ -1330,24 +1330,12 @@ pub fn build_exp_expr<'a, 'ctx, 'env>(
|
|||
index,
|
||||
structure,
|
||||
wrapped: Wrapped::SingleElementRecord,
|
||||
field_layouts,
|
||||
..
|
||||
} => {
|
||||
match load_symbol_and_layout(env, scope, structure) {
|
||||
(StructValue(argument), Layout::Struct(fields)) if fields.len() > 1 =>
|
||||
// TODO so sometimes a value gets Wrapped::SingleElementRecord
|
||||
// but still has multiple fields...
|
||||
{
|
||||
env.builder
|
||||
.build_extract_value(
|
||||
argument,
|
||||
*index as u32,
|
||||
env.arena
|
||||
.alloc(format!("struct_field_access_single_element{}", index)),
|
||||
)
|
||||
.unwrap()
|
||||
}
|
||||
(other, _) => other,
|
||||
}
|
||||
debug_assert_eq!(field_layouts.len(), 1);
|
||||
debug_assert_eq!(*index, 0);
|
||||
load_symbol(env, scope, structure)
|
||||
}
|
||||
|
||||
AccessAtIndex {
|
||||
|
@ -2153,12 +2141,12 @@ pub fn build_exp_stmt<'a, 'ctx, 'env>(
|
|||
// This doesn't currently do anything
|
||||
context.i64_type().const_zero().into()
|
||||
}
|
||||
Inc(symbol, cont) => {
|
||||
Inc(symbol, inc_amount, cont) => {
|
||||
let (value, layout) = load_symbol_and_layout(env, scope, symbol);
|
||||
let layout = layout.clone();
|
||||
|
||||
if layout.contains_refcounted() {
|
||||
increment_refcount_layout(env, parent, layout_ids, value, &layout);
|
||||
increment_refcount_layout(env, parent, layout_ids, *inc_amount, value, &layout);
|
||||
}
|
||||
|
||||
build_exp_stmt(env, layout_ids, scope, parent, cont)
|
||||
|
@ -2291,10 +2279,18 @@ pub fn complex_bitcast<'ctx>(
|
|||
) -> BasicValueEnum<'ctx> {
|
||||
use inkwell::types::BasicType;
|
||||
|
||||
// we can't use the more simple
|
||||
// builder.build_bitcast(from_value, to_type, "cast_basic_basic")
|
||||
// because this does not allow some (valid) bitcasts
|
||||
|
||||
use BasicTypeEnum::*;
|
||||
match (from_value.get_type(), to_type) {
|
||||
(PointerType(_), PointerType(_)) => {
|
||||
// we can't use the more straightforward bitcast in all cases
|
||||
// it seems like a bitcast only works on integers and pointers
|
||||
// and crucially does not work not on arrays
|
||||
builder.build_bitcast(from_value, to_type, name)
|
||||
}
|
||||
_ => {
|
||||
// store the value in memory
|
||||
let argument_pointer = builder.build_alloca(from_value.get_type(), "cast_alloca");
|
||||
builder.build_store(argument_pointer, from_value);
|
||||
|
@ -2310,6 +2306,8 @@ pub fn complex_bitcast<'ctx>(
|
|||
|
||||
builder.build_load(to_type_pointer, "cast_value")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn extract_tag_discriminant_struct<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
|
|
|
@ -576,7 +576,7 @@ pub fn list_get_unsafe<'a, 'ctx, 'env>(
|
|||
|
||||
let result = builder.build_load(elem_ptr, "List.get");
|
||||
|
||||
increment_refcount_layout(env, parent, layout_ids, result, elem_layout);
|
||||
increment_refcount_layout(env, parent, layout_ids, 1, result, elem_layout);
|
||||
|
||||
result
|
||||
}
|
||||
|
@ -1369,11 +1369,11 @@ macro_rules! list_map_help {
|
|||
let list_ptr = load_list_ptr(builder, list_wrapper, ptr_type);
|
||||
|
||||
let list_loop = |index, before_elem| {
|
||||
increment_refcount_layout($env, parent, layout_ids, before_elem, elem_layout);
|
||||
increment_refcount_layout($env, parent, layout_ids, 1, before_elem, elem_layout);
|
||||
|
||||
let arguments = match closure_info {
|
||||
Some((closure_data_layout, closure_data)) => {
|
||||
increment_refcount_layout( $env, parent, layout_ids, closure_data, closure_data_layout);
|
||||
increment_refcount_layout( $env, parent, layout_ids, 1, closure_data, closure_data_layout);
|
||||
|
||||
bumpalo::vec![in $env.arena; before_elem, closure_data]
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -13,6 +13,8 @@ mod helpers;
|
|||
|
||||
#[cfg(test)]
|
||||
mod gen_primitives {
|
||||
use roc_std::RocStr;
|
||||
|
||||
#[test]
|
||||
fn basic_int() {
|
||||
assert_evals_to!("123", 123, i64);
|
||||
|
@ -1268,7 +1270,6 @@ mod gen_primitives {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[ignore]
|
||||
fn rbtree_insert() {
|
||||
assert_non_opt_evals_to!(
|
||||
indoc!(
|
||||
|
@ -1338,54 +1339,20 @@ mod gen_primitives {
|
|||
_ ->
|
||||
Node color key value left right
|
||||
|
||||
main : RedBlackTree (Int *) {}
|
||||
show : RedBlackTree I64 {} -> Str
|
||||
show = \tree ->
|
||||
when tree is
|
||||
Empty -> "Empty"
|
||||
Node _ _ _ _ _ -> "Node"
|
||||
|
||||
|
||||
main : Str
|
||||
main =
|
||||
insert 0 {} Empty
|
||||
show (insert 0 {} Empty)
|
||||
"#
|
||||
),
|
||||
1,
|
||||
i64
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ignore]
|
||||
fn rbtree_balance_inc_dec() {
|
||||
// TODO does not define a variable correctly, but all is well with the type signature
|
||||
assert_non_opt_evals_to!(
|
||||
indoc!(
|
||||
r#"
|
||||
app "test" provides [ main ] to "./platform"
|
||||
|
||||
NodeColor : [ Red, Black ]
|
||||
|
||||
RedBlackTree k : [ Node NodeColor k (RedBlackTree k) (RedBlackTree k), Empty ]
|
||||
|
||||
# balance : NodeColor, k, RedBlackTree k, RedBlackTree k -> RedBlackTree k
|
||||
balance = \color, key, left, right ->
|
||||
when right is
|
||||
Node Red rK rLeft rRight ->
|
||||
when left is
|
||||
Node Red _ _ _ ->
|
||||
Node
|
||||
Red
|
||||
key
|
||||
Empty
|
||||
Empty
|
||||
|
||||
_ ->
|
||||
Node color rK (Node Red key left rLeft) rRight
|
||||
|
||||
_ ->
|
||||
Empty
|
||||
|
||||
main : RedBlackTree (Int *)
|
||||
main =
|
||||
balance Red 0 Empty Empty
|
||||
"#
|
||||
),
|
||||
0,
|
||||
i64
|
||||
RocStr::from_slice("Node".as_bytes()),
|
||||
RocStr
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -1413,6 +1380,47 @@ mod gen_primitives {
|
|||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ignore]
|
||||
fn rbtree_layout_issue() {
|
||||
// there is a flex var in here somewhere that blows up layout creation
|
||||
assert_non_opt_evals_to!(
|
||||
indoc!(
|
||||
r#"
|
||||
app "test" provides [ main ] to "./platform"
|
||||
|
||||
NodeColor : [ Red, Black ]
|
||||
|
||||
RedBlackTree k v : [ Node NodeColor k v (RedBlackTree k v) (RedBlackTree k v), Empty ]
|
||||
|
||||
# balance : NodeColor, k, v, RedBlackTree k v -> RedBlackTree k v
|
||||
balance = \color, key, value, right ->
|
||||
when right is
|
||||
Node Red _ _ rLeft rRight ->
|
||||
Node color key value rLeft rRight
|
||||
|
||||
|
||||
_ ->
|
||||
Empty
|
||||
|
||||
show : RedBlackTree * * -> Str
|
||||
show = \tree ->
|
||||
when tree is
|
||||
Empty -> "Empty"
|
||||
Node _ _ _ _ _ -> "Node"
|
||||
|
||||
zero : I64
|
||||
zero = 0
|
||||
|
||||
main : Str
|
||||
main = show (balance Red zero zero Empty)
|
||||
"#
|
||||
),
|
||||
RocStr::from_slice("Empty".as_bytes()),
|
||||
RocStr
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ignore]
|
||||
fn rbtree_balance_mono_problem() {
|
||||
|
@ -1450,13 +1458,19 @@ mod gen_primitives {
|
|||
_ ->
|
||||
Empty
|
||||
|
||||
main : RedBlackTree (Int *) (Int *)
|
||||
main =
|
||||
balance Red 0 0 Empty Empty
|
||||
show : RedBlackTree * * -> Str
|
||||
show = \tree ->
|
||||
when tree is
|
||||
Empty -> "Empty"
|
||||
Node _ _ _ _ _ -> "Node"
|
||||
|
||||
|
||||
main : Str
|
||||
main = show (balance Red 0 0 Empty Empty)
|
||||
"#
|
||||
),
|
||||
1,
|
||||
i64
|
||||
RocStr::from_slice("Empty".as_bytes()),
|
||||
RocStr
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -1928,12 +1942,8 @@ mod gen_primitives {
|
|||
r#"
|
||||
app "test" provides [ main ] to "./platform"
|
||||
|
||||
# RoseTree
|
||||
Tree a : [ Tree a (List (Tree a)) ]
|
||||
|
||||
# tree : a, List (Tree a) -> Tree a
|
||||
# tree = \a, t -> Tree a t
|
||||
|
||||
singleton : a -> Tree a
|
||||
singleton = \x -> Tree x []
|
||||
|
||||
|
@ -2115,4 +2125,36 @@ mod gen_primitives {
|
|||
i64
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn multiple_increment() {
|
||||
// the `leaf` value will be incremented multiple times at once
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
r#"
|
||||
app "test" provides [ main ] to "./platform"
|
||||
|
||||
Color : [ Red, Black ]
|
||||
|
||||
Tree a b : [ Leaf, Node Color (Tree a b) a b (Tree a b) ]
|
||||
|
||||
Map : Tree I64 Bool
|
||||
|
||||
main : I64
|
||||
main =
|
||||
leaf : Map
|
||||
leaf = Leaf
|
||||
|
||||
m : Map
|
||||
m = Node Black (Node Black leaf 10 False leaf) 11 False (Node Black leaf 12 False (Node Red leaf 13 False leaf))
|
||||
|
||||
when m is
|
||||
Leaf -> 0
|
||||
Node _ _ _ _ _ -> 1
|
||||
"#
|
||||
),
|
||||
1,
|
||||
i64
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -960,4 +960,27 @@ mod gen_tags {
|
|||
|x: &i64| *x
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn newtype_wrapper() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
r#"
|
||||
app "test" provides [ main ] to "./platform"
|
||||
|
||||
ConsList a : [ Nil, Cons a (ConsList a) ]
|
||||
|
||||
foo : ConsList I64 -> ConsList I64
|
||||
foo = \t ->
|
||||
when Delmin (Del t 0.0) is
|
||||
Delmin (Del ry _) -> Cons 42 ry
|
||||
|
||||
main = foo Nil
|
||||
"#
|
||||
),
|
||||
42,
|
||||
&i64,
|
||||
|x: &i64| *x
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -68,15 +68,6 @@ pub fn helper<'a>(
|
|||
debug_assert_eq!(exposed_to_host.len(), 1);
|
||||
let main_fn_symbol = exposed_to_host.keys().copied().next().unwrap();
|
||||
|
||||
let (_, main_fn_layout) = match procedures.keys().find(|(s, _)| *s == main_fn_symbol) {
|
||||
Some(found) => found.clone(),
|
||||
None => panic!(
|
||||
"The main function symbol {:?} does not have a procedure in {:?}",
|
||||
main_fn_symbol,
|
||||
&procedures.keys()
|
||||
),
|
||||
};
|
||||
|
||||
let mut lines = Vec::new();
|
||||
// errors whose reporting we delay (so we can see that code gen generates runtime errors)
|
||||
let mut delayed_errors = Vec::new();
|
||||
|
@ -160,6 +151,15 @@ pub fn helper<'a>(
|
|||
}
|
||||
}
|
||||
|
||||
let (_, main_fn_layout) = match procedures.keys().find(|(s, _)| *s == main_fn_symbol) {
|
||||
Some(found) => found.clone(),
|
||||
None => panic!(
|
||||
"The main function symbol {:?} does not have a procedure in {:?}",
|
||||
main_fn_symbol,
|
||||
&procedures.keys()
|
||||
),
|
||||
};
|
||||
|
||||
let module = roc_gen::llvm::build::module_from_builtins(context, "app");
|
||||
|
||||
// strip Zig debug stuff
|
||||
|
|
|
@ -381,7 +381,7 @@ where
|
|||
self.set_last_seen(*sym, stmt);
|
||||
}
|
||||
Stmt::Rethrow => {}
|
||||
Stmt::Inc(sym, following) => {
|
||||
Stmt::Inc(sym, _inc, following) => {
|
||||
self.set_last_seen(*sym, stmt);
|
||||
self.scan_ast(following);
|
||||
}
|
||||
|
|
|
@ -1803,6 +1803,8 @@ fn update<'a>(
|
|||
if state.dependencies.solved_all() && state.goal_phase == Phase::MakeSpecializations {
|
||||
debug_assert!(work.is_empty(), "still work remaining {:?}", &work);
|
||||
|
||||
Proc::insert_refcount_operations(arena, &mut state.procedures);
|
||||
|
||||
// display the mono IR of the module, for debug purposes
|
||||
if roc_mono::ir::PRETTY_PRINT_IR_SYMBOLS {
|
||||
let procs_string = state
|
||||
|
@ -1816,8 +1818,6 @@ fn update<'a>(
|
|||
println!("{}", result);
|
||||
}
|
||||
|
||||
Proc::insert_refcount_operations(arena, &mut state.procedures);
|
||||
|
||||
msg_tx
|
||||
.send(Msg::FinishedAllSpecialization {
|
||||
subs,
|
||||
|
|
|
@ -168,7 +168,7 @@ impl<'a> ParamMap<'a> {
|
|||
stack.extend(branches.iter().map(|b| &b.1));
|
||||
stack.push(default_branch);
|
||||
}
|
||||
Inc(_, _) | Dec(_, _) => unreachable!("these have not been introduced yet"),
|
||||
Inc(_, _, _) | Dec(_, _) => unreachable!("these have not been introduced yet"),
|
||||
|
||||
Ret(_) | Rethrow | Jump(_, _) | RuntimeError(_) => {
|
||||
// these are terminal, do nothing
|
||||
|
@ -513,7 +513,7 @@ impl<'a> BorrowInfState<'a> {
|
|||
}
|
||||
self.collect_stmt(default_branch);
|
||||
}
|
||||
Inc(_, _) | Dec(_, _) => unreachable!("these have not been introduced yet"),
|
||||
Inc(_, _, _) | Dec(_, _) => unreachable!("these have not been introduced yet"),
|
||||
|
||||
Ret(_) | RuntimeError(_) | Rethrow => {
|
||||
// these are terminal, do nothing
|
||||
|
|
|
@ -1027,6 +1027,8 @@ fn path_to_expr_help<'a>(
|
|||
|
||||
debug_assert!(*index < field_layouts.len() as u64);
|
||||
|
||||
debug_assert_eq!(field_layouts.len(), 1);
|
||||
|
||||
let inner_layout = field_layouts[*index as usize].clone();
|
||||
let inner_expr = Expr::AccessAtIndex {
|
||||
index: *index,
|
||||
|
|
|
@ -52,7 +52,7 @@ pub fn occuring_variables(stmt: &Stmt<'_>) -> (MutSet<Symbol>, MutSet<Symbol>) {
|
|||
|
||||
Rethrow => {}
|
||||
|
||||
Inc(symbol, cont) | Dec(symbol, cont) => {
|
||||
Inc(symbol, _, cont) | Dec(symbol, cont) => {
|
||||
result.insert(*symbol);
|
||||
stack.push(cont);
|
||||
}
|
||||
|
@ -262,7 +262,9 @@ impl<'a> Context<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
fn add_inc(&self, symbol: Symbol, stmt: &'a Stmt<'a>) -> &'a Stmt<'a> {
|
||||
fn add_inc(&self, symbol: Symbol, inc_amount: u64, stmt: &'a Stmt<'a>) -> &'a Stmt<'a> {
|
||||
debug_assert!(inc_amount > 0);
|
||||
|
||||
let info = self.get_var_info(symbol);
|
||||
|
||||
if info.persistent {
|
||||
|
@ -275,7 +277,7 @@ impl<'a> Context<'a> {
|
|||
return stmt;
|
||||
}
|
||||
|
||||
self.arena.alloc(Stmt::Inc(symbol, stmt))
|
||||
self.arena.alloc(Stmt::Inc(symbol, inc_amount, stmt))
|
||||
}
|
||||
|
||||
fn add_dec(&self, symbol: Symbol, stmt: &'a Stmt<'a>) -> &'a Stmt<'a> {
|
||||
|
@ -335,11 +337,8 @@ impl<'a> Context<'a> {
|
|||
num_consumptions - 1
|
||||
};
|
||||
|
||||
// verify that this is indeed always 1
|
||||
debug_assert!(num_incs <= 1);
|
||||
|
||||
if num_incs == 1 {
|
||||
b = self.add_inc(*x, b)
|
||||
if num_incs >= 1 {
|
||||
b = self.add_inc(*x, num_incs as u64, b)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -524,7 +523,7 @@ impl<'a> Context<'a> {
|
|||
let b = self.add_dec_if_needed(x, b, b_live_vars);
|
||||
let info_x = self.get_var_info(x);
|
||||
let b = if info_x.consume {
|
||||
self.add_inc(z, b)
|
||||
self.add_inc(z, 1, b)
|
||||
} else {
|
||||
b
|
||||
};
|
||||
|
@ -786,7 +785,7 @@ impl<'a> Context<'a> {
|
|||
live_vars.insert(*x);
|
||||
|
||||
if info.reference && !info.consume {
|
||||
(self.add_inc(*x, stmt), live_vars)
|
||||
(self.add_inc(*x, 1, stmt), live_vars)
|
||||
} else {
|
||||
(stmt, live_vars)
|
||||
}
|
||||
|
@ -851,7 +850,7 @@ impl<'a> Context<'a> {
|
|||
(switch, case_live_vars)
|
||||
}
|
||||
|
||||
RuntimeError(_) | Inc(_, _) | Dec(_, _) => (stmt, MutSet::default()),
|
||||
RuntimeError(_) | Inc(_, _, _) | Dec(_, _) => (stmt, MutSet::default()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -902,7 +901,7 @@ pub fn collect_stmt(
|
|||
vars
|
||||
}
|
||||
|
||||
Inc(symbol, cont) | Dec(symbol, cont) => {
|
||||
Inc(symbol, _, cont) | Dec(symbol, cont) => {
|
||||
vars.insert(*symbol);
|
||||
collect_stmt(cont, jp_live_vars, vars)
|
||||
}
|
||||
|
|
|
@ -766,7 +766,7 @@ pub enum Stmt<'a> {
|
|||
},
|
||||
Ret(Symbol),
|
||||
Rethrow,
|
||||
Inc(Symbol, &'a Stmt<'a>),
|
||||
Inc(Symbol, u64, &'a Stmt<'a>),
|
||||
Dec(Symbol, &'a Stmt<'a>),
|
||||
Join {
|
||||
id: JoinPointId,
|
||||
|
@ -1267,12 +1267,19 @@ impl<'a> Stmt<'a> {
|
|||
.append(alloc.intersperse(it, alloc.space()))
|
||||
.append(";")
|
||||
}
|
||||
Inc(symbol, cont) => alloc
|
||||
Inc(symbol, 1, cont) => alloc
|
||||
.text("inc ")
|
||||
.append(symbol_to_doc(alloc, *symbol))
|
||||
.append(";")
|
||||
.append(alloc.hardline())
|
||||
.append(cont.to_doc(alloc)),
|
||||
Inc(symbol, n, cont) => alloc
|
||||
.text("inc ")
|
||||
.append(alloc.text(format!("{}", n)))
|
||||
.append(symbol_to_doc(alloc, *symbol))
|
||||
.append(";")
|
||||
.append(alloc.hardline())
|
||||
.append(cont.to_doc(alloc)),
|
||||
Dec(symbol, cont) => alloc
|
||||
.text("dec ")
|
||||
.append(symbol_to_doc(alloc, *symbol))
|
||||
|
@ -3102,7 +3109,8 @@ pub fn with_hole<'a>(
|
|||
);
|
||||
|
||||
for (loc_cond, loc_then) in branches.into_iter().rev() {
|
||||
let branching_symbol = env.unique_symbol();
|
||||
let branching_symbol = possible_reuse_symbol(env, procs, &loc_cond.value);
|
||||
|
||||
let then = with_hole(
|
||||
env,
|
||||
loc_then.value,
|
||||
|
@ -3123,14 +3131,14 @@ pub fn with_hole<'a>(
|
|||
);
|
||||
|
||||
// add condition
|
||||
stmt = with_hole(
|
||||
stmt = assign_to_symbol(
|
||||
env,
|
||||
loc_cond.value,
|
||||
cond_var,
|
||||
procs,
|
||||
layout_cache,
|
||||
cond_var,
|
||||
loc_cond,
|
||||
branching_symbol,
|
||||
env.arena.alloc(stmt),
|
||||
stmt,
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -3289,7 +3297,10 @@ pub fn with_hole<'a>(
|
|||
|
||||
match Wrapped::opt_from_layout(&record_layout) {
|
||||
Some(result) => result,
|
||||
None => Wrapped::SingleElementRecord,
|
||||
None => {
|
||||
debug_assert_eq!(field_layouts.len(), 1);
|
||||
Wrapped::SingleElementRecord
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -4697,8 +4708,8 @@ fn substitute_in_stmt_help<'a>(
|
|||
Some(s) => Some(arena.alloc(Ret(s))),
|
||||
None => None,
|
||||
},
|
||||
Inc(symbol, cont) => match substitute_in_stmt_help(arena, cont, subs) {
|
||||
Some(cont) => Some(arena.alloc(Inc(*symbol, cont))),
|
||||
Inc(symbol, inc, cont) => match substitute_in_stmt_help(arena, cont, subs) {
|
||||
Some(cont) => Some(arena.alloc(Inc(*symbol, *inc, cont))),
|
||||
None => None,
|
||||
},
|
||||
Dec(symbol, cont) => match substitute_in_stmt_help(arena, cont, subs) {
|
||||
|
@ -5619,7 +5630,11 @@ fn call_by_name<'a>(
|
|||
partial_proc,
|
||||
) {
|
||||
Ok((proc, layout)) => {
|
||||
debug_assert_eq!(full_layout, layout);
|
||||
debug_assert_eq!(
|
||||
&full_layout, &layout,
|
||||
"\n\n{:?}\n\n{:?}",
|
||||
full_layout, layout
|
||||
);
|
||||
let function_layout =
|
||||
FunctionLayouts::from_layout(env.arena, layout);
|
||||
|
||||
|
@ -6070,7 +6085,12 @@ fn from_can_pattern_help<'a>(
|
|||
|
||||
let mut mono_args = Vec::with_capacity_in(arguments.len(), env.arena);
|
||||
|
||||
debug_assert_eq!(arguments.len(), argument_layouts[1..].len());
|
||||
debug_assert_eq!(
|
||||
arguments.len(),
|
||||
argument_layouts[1..].len(),
|
||||
"{:?}",
|
||||
tag_name
|
||||
);
|
||||
let it = argument_layouts[1..].iter();
|
||||
|
||||
for ((_, loc_pat), layout) in arguments.iter().zip(it) {
|
||||
|
|
|
@ -1806,8 +1806,8 @@ pub fn list_layout_from_elem<'a>(
|
|||
// If this was still a (List *) then it must have been an empty list
|
||||
Ok(Layout::Builtin(Builtin::EmptyList))
|
||||
}
|
||||
content => {
|
||||
let elem_layout = Layout::new_help(env, elem_var, content)?;
|
||||
_ => {
|
||||
let elem_layout = Layout::from_var(env, elem_var)?;
|
||||
|
||||
// This is a normal list.
|
||||
Ok(Layout::Builtin(Builtin::List(
|
||||
|
|
|
@ -228,8 +228,8 @@ fn insert_jumps<'a>(
|
|||
None
|
||||
}
|
||||
}
|
||||
Inc(symbol, cont) => match insert_jumps(arena, cont, goal_id, needle) {
|
||||
Some(cont) => Some(arena.alloc(Inc(*symbol, cont))),
|
||||
Inc(symbol, inc, cont) => match insert_jumps(arena, cont, goal_id, needle) {
|
||||
Some(cont) => Some(arena.alloc(Inc(*symbol, *inc, cont))),
|
||||
None => None,
|
||||
},
|
||||
Dec(symbol, cont) => match insert_jumps(arena, cont, goal_id, needle) {
|
||||
|
|
|
@ -145,6 +145,9 @@ pub enum RuntimeError {
|
|||
InvalidUnicodeCodePoint(Region),
|
||||
|
||||
/// When the author specifies a type annotation but no implementation
|
||||
NoImplementationNamed {
|
||||
def_symbol: Symbol,
|
||||
},
|
||||
NoImplementation,
|
||||
|
||||
/// cases where the `[]` value (or equivalently, `forall a. a`) pops up
|
||||
|
|
|
@ -635,7 +635,7 @@ fn pretty_runtime_error<'b>(
|
|||
region
|
||||
);
|
||||
}
|
||||
RuntimeError::NoImplementation => todo!("no implementation, unreachable"),
|
||||
RuntimeError::NoImplementation | RuntimeError::NoImplementationNamed { .. } => todo!("no implementation, unreachable"),
|
||||
RuntimeError::NonExhaustivePattern => {
|
||||
unreachable!("not currently reported (but can blow up at runtime)")
|
||||
}
|
||||
|
|
|
@ -371,7 +371,7 @@ impl SolvedType {
|
|||
|
||||
match subs.get_without_compacting(var).content {
|
||||
FlexVar(_) => SolvedType::Flex(VarId::from_var(var, subs)),
|
||||
RecursionVar { .. } => todo!(),
|
||||
RecursionVar { .. } => SolvedType::Flex(VarId::from_var(var, subs)),
|
||||
RigidVar(name) => SolvedType::Rigid(name),
|
||||
Structure(flat_type) => Self::from_flat_type(subs, recursion_vars, flat_type),
|
||||
Alias(symbol, args, actual_var) => {
|
||||
|
|
1
examples/.gitignore
vendored
1
examples/.gitignore
vendored
|
@ -7,4 +7,5 @@ roc_app.bc
|
|||
benchmarks/nqueens
|
||||
benchmarks/deriv
|
||||
benchmarks/cfold
|
||||
benchmarks/rbtree-insert
|
||||
effect-example
|
||||
|
|
|
@ -5,7 +5,7 @@ app "nqueens"
|
|||
|
||||
main : Task.Task {} []
|
||||
main =
|
||||
queens 10
|
||||
queens 6
|
||||
|> Str.fromInt
|
||||
|> Task.putLine
|
||||
|
||||
|
|
123
examples/benchmarks/RBTreeCk.roc
Normal file
123
examples/benchmarks/RBTreeCk.roc
Normal file
|
@ -0,0 +1,123 @@
|
|||
app "rbtree-ck"
|
||||
packages { base: "platform" }
|
||||
imports [base.Task]
|
||||
provides [ main ] to base
|
||||
|
||||
|
||||
Color : [ Red, Black ]
|
||||
|
||||
Tree a b : [ Leaf, Node Color (Tree a b) a b (Tree a b) ]
|
||||
|
||||
Map : Tree I64 Bool
|
||||
|
||||
ConsList a : [ Nil, Cons a (ConsList a) ]
|
||||
|
||||
makeMap : I64, I64 -> ConsList Map
|
||||
makeMap = \freq, n ->
|
||||
makeMapHelp freq n Leaf Nil
|
||||
|
||||
makeMapHelp : I64, I64, Map, ConsList Map -> ConsList Map
|
||||
makeMapHelp = \freq, n, m, acc ->
|
||||
when n is
|
||||
0 -> Cons m acc
|
||||
_ ->
|
||||
powerOf10 =
|
||||
(n % 10 |> resultWithDefault 0) == 0
|
||||
|
||||
|
||||
m1 = insert m n powerOf10
|
||||
|
||||
isFrequency =
|
||||
(n % freq |> resultWithDefault 0) == 0
|
||||
|
||||
x = (if isFrequency then (Cons m1 acc) else acc)
|
||||
makeMapHelp freq (n-1) m1 x
|
||||
|
||||
fold : (a, b, omega -> omega), Tree a b, omega -> omega
|
||||
fold = \f, tree, b ->
|
||||
when tree is
|
||||
Leaf -> b
|
||||
Node _ l k v r -> fold f r (f k v (fold f l b))
|
||||
|
||||
resultWithDefault : Result a e, a -> a
|
||||
resultWithDefault = \res, default ->
|
||||
when res is
|
||||
Ok v -> v
|
||||
Err _ -> default
|
||||
|
||||
main : Task.Task {} []
|
||||
main =
|
||||
ms : ConsList Map
|
||||
ms = makeMap 5 5 # 42_000_00
|
||||
|
||||
when ms is
|
||||
Cons head _ ->
|
||||
val = fold (\_, v, r -> if v then r + 1 else r) head 0
|
||||
val
|
||||
|> Str.fromInt
|
||||
|> Task.putLine
|
||||
|
||||
Nil ->
|
||||
Task.putLine "fail"
|
||||
|
||||
insert : Map, I64, Bool -> Map
|
||||
insert = \t, k, v -> if isRed t then setBlack (ins t k v) else ins t k v
|
||||
|
||||
|
||||
setBlack : Tree a b -> Tree a b
|
||||
setBlack = \tree ->
|
||||
when tree is
|
||||
Node _ l k v r -> Node Black l k v r
|
||||
_ -> tree
|
||||
|
||||
isRed : Tree a b -> Bool
|
||||
isRed = \tree ->
|
||||
when tree is
|
||||
Node Red _ _ _ _ -> True
|
||||
_ -> False
|
||||
|
||||
lt = \x, y -> x < y
|
||||
|
||||
ins : Map, I64, Bool -> Map
|
||||
ins = \tree, kx, vx ->
|
||||
when tree is
|
||||
Leaf ->
|
||||
Node Red Leaf kx vx Leaf
|
||||
|
||||
Node Red a ky vy b ->
|
||||
if lt kx ky then
|
||||
Node Red (ins a kx vx) ky vy b
|
||||
else if lt ky kx then
|
||||
Node Red a ky vy (ins b kx vx)
|
||||
else
|
||||
Node Red a ky vy (ins b kx vx)
|
||||
|
||||
Node Black a ky vy b ->
|
||||
if lt kx ky then
|
||||
(if isRed a then balance1 (Node Black Leaf ky vy b) (ins a kx vx) else Node Black (ins a kx vx) ky vy b)
|
||||
else if lt ky kx then
|
||||
(if isRed b then balance2 (Node Black a ky vy Leaf) (ins b kx vx) else Node Black a ky vy (ins b kx vx))
|
||||
else
|
||||
Node Black a kx vx b
|
||||
|
||||
balance1 : Map, Map -> Map
|
||||
balance1 = \tree1, tree2 ->
|
||||
when tree1 is
|
||||
Leaf -> Leaf
|
||||
Node _ _ kv vv t ->
|
||||
when tree2 is
|
||||
Node _ (Node Red l kx vx r1) ky vy r2 -> Node Red (Node Black l kx vx r1) ky vy (Node Black r2 kv vv t)
|
||||
Node _ l1 ky vy (Node Red l2 kx vx r) -> Node Red (Node Black l1 ky vy l2) kx vx (Node Black r kv vv t)
|
||||
Node _ l ky vy r -> Node Black (Node Red l ky vy r) kv vv t
|
||||
Leaf -> Leaf
|
||||
|
||||
balance2 : Map, Map -> Map
|
||||
balance2 = \tree1, tree2 ->
|
||||
when tree1 is
|
||||
Leaf -> Leaf
|
||||
Node _ t kv vv _ ->
|
||||
when tree2 is
|
||||
Node _ (Node Red l kx1 vx1 r1) ky vy r2 -> Node Red (Node Black t kv vv l) kx1 vx1 (Node Black r1 ky vy r2)
|
||||
Node _ l1 ky vy (Node Red l2 kx2 vx2 r2) -> Node Red (Node Black t kv vv l1) ky vy (Node Black l2 kx2 vx2 r2)
|
||||
Node _ l ky vy r -> Node Black t kv vv (Node Red l ky vy r)
|
||||
Leaf -> Leaf
|
216
examples/benchmarks/RBTreeDel.roc
Normal file
216
examples/benchmarks/RBTreeDel.roc
Normal file
|
@ -0,0 +1,216 @@
|
|||
app "rbtree-del"
|
||||
packages { base: "platform" }
|
||||
imports [base.Task]
|
||||
provides [ main ] to base
|
||||
|
||||
|
||||
Color : [ Red, Black ]
|
||||
|
||||
Tree a b : [ Leaf, Node Color (Tree a b) a b (Tree a b) ]
|
||||
|
||||
Map : Tree I64 Bool
|
||||
|
||||
ConsList a : [ Nil, Cons a (ConsList a) ]
|
||||
|
||||
main : Task.Task {} []
|
||||
main =
|
||||
# benchmarks use 4_200_000
|
||||
m = makeMap 420
|
||||
|
||||
val = fold (\_, v, r -> if v then r + 1 else r) m 0
|
||||
|
||||
val
|
||||
|> Str.fromInt
|
||||
|> Task.putLine
|
||||
|
||||
boom : Str -> a
|
||||
boom = \_ -> boom ""
|
||||
|
||||
makeMap : I64 -> Map
|
||||
makeMap = \n ->
|
||||
makeMapHelp n n Leaf
|
||||
|
||||
makeMapHelp : I64, I64, Map -> Map
|
||||
makeMapHelp = \total, n, m ->
|
||||
when n is
|
||||
0 -> m
|
||||
_ ->
|
||||
n1 = n - 1
|
||||
|
||||
powerOf10 =
|
||||
(n % 10 |> resultWithDefault 0) == 0
|
||||
|
||||
t1 = insert m n powerOf10
|
||||
|
||||
isFrequency =
|
||||
(n % 4 |> resultWithDefault 0) == 0
|
||||
|
||||
key = n1 + ((total - n1) // 5 |> resultWithDefault 0)
|
||||
t2 = if isFrequency then delete t1 key else t1
|
||||
|
||||
makeMapHelp total n1 t2
|
||||
|
||||
fold : (a, b, omega -> omega), Tree a b, omega -> omega
|
||||
fold = \f, tree, b ->
|
||||
when tree is
|
||||
Leaf -> b
|
||||
Node _ l k v r -> fold f r (f k v (fold f l b))
|
||||
|
||||
depth : Tree * * -> I64
|
||||
depth = \tree ->
|
||||
when tree is
|
||||
Leaf -> 1
|
||||
Node _ l _ _ r -> 1 + depth l + depth r
|
||||
|
||||
resultWithDefault : Result a e, a -> a
|
||||
resultWithDefault = \res, default ->
|
||||
when res is
|
||||
Ok v -> v
|
||||
Err _ -> default
|
||||
|
||||
|
||||
insert : Map, I64, Bool -> Map
|
||||
insert = \t, k, v -> if isRed t then setBlack (ins t k v) else ins t k v
|
||||
|
||||
|
||||
setBlack : Tree a b -> Tree a b
|
||||
setBlack = \tree ->
|
||||
when tree is
|
||||
Node _ l k v r -> Node Black l k v r
|
||||
_ -> tree
|
||||
|
||||
isRed : Tree a b -> Bool
|
||||
isRed = \tree ->
|
||||
when tree is
|
||||
Node Red _ _ _ _ -> True
|
||||
_ -> False
|
||||
|
||||
lt = \x, y -> x < y
|
||||
|
||||
ins : Map, I64, Bool -> Map
|
||||
ins = \tree, kx, vx ->
|
||||
when tree is
|
||||
Leaf ->
|
||||
Node Red Leaf kx vx Leaf
|
||||
|
||||
Node Red a ky vy b ->
|
||||
if lt kx ky then
|
||||
Node Red (ins a kx vx) ky vy b
|
||||
else if lt ky kx then
|
||||
Node Red a ky vy (ins b kx vx)
|
||||
else
|
||||
Node Red a ky vy (ins b kx vx)
|
||||
|
||||
Node Black a ky vy b ->
|
||||
if lt kx ky then
|
||||
(if isRed a then balanceLeft (ins a kx vx) ky vy b else Node Black (ins a kx vx) ky vy b)
|
||||
else if lt ky kx then
|
||||
(if isRed b then balanceRight a ky vy (ins b kx vx) else Node Black a ky vy (ins b kx vx))
|
||||
else Node Black a kx vx b
|
||||
|
||||
balanceLeft : Tree a b, a, b, Tree a b -> Tree a b
|
||||
balanceLeft = \l, k, v, r ->
|
||||
when l is
|
||||
Leaf -> Leaf
|
||||
Node _ (Node Red lx kx vx rx) ky vy ry
|
||||
-> Node Red (Node Black lx kx vx rx) ky vy (Node Black ry k v r)
|
||||
Node _ ly ky vy (Node Red lx kx vx rx)
|
||||
-> Node Red (Node Black ly ky vy lx) kx vx (Node Black rx k v r)
|
||||
Node _ lx kx vx rx
|
||||
-> Node Black (Node Red lx kx vx rx) k v r
|
||||
|
||||
balanceRight : Tree a b, a, b, Tree a b -> Tree a b
|
||||
balanceRight = \l, k, v, r ->
|
||||
when r is
|
||||
Leaf -> Leaf
|
||||
Node _ (Node Red lx kx vx rx) ky vy ry
|
||||
-> Node Red (Node Black l k v lx) kx vx (Node Black rx ky vy ry)
|
||||
Node _ lx kx vx (Node Red ly ky vy ry)
|
||||
-> Node Red (Node Black l k v lx) kx vx (Node Black ly ky vy ry)
|
||||
Node _ lx kx vx rx
|
||||
-> Node Black l k v (Node Red lx kx vx rx)
|
||||
|
||||
isBlack : Color -> Bool
|
||||
isBlack = \c ->
|
||||
when c is
|
||||
Black -> True
|
||||
Red -> False
|
||||
|
||||
|
||||
Del a b : [ Del (Tree a b) Bool ]
|
||||
|
||||
setRed : Map -> Map
|
||||
setRed = \t ->
|
||||
when t is
|
||||
Node _ l k v r -> Node Red l k v r
|
||||
_ -> t
|
||||
|
||||
|
||||
|
||||
makeBlack : Map -> Del I64 Bool
|
||||
makeBlack = \t ->
|
||||
when t is
|
||||
Node Red l k v r -> Del (Node Black l k v r) False
|
||||
_ -> Del t True
|
||||
|
||||
|
||||
rebalanceLeft = \c, l, k, v, r ->
|
||||
when l is
|
||||
Node Black _ _ _ _ -> Del (balanceLeft (setRed l) k v r) (isBlack c)
|
||||
Node Red lx kx vx rx -> Del (Node Black lx kx vx (balanceLeft (setRed rx) k v r)) False
|
||||
_ -> boom "unreachable"
|
||||
|
||||
rebalanceRight = \c, l, k, v, r ->
|
||||
when r is
|
||||
Node Black _ _ _ _ -> Del (balanceRight l k v (setRed r)) (isBlack c)
|
||||
Node Red lx kx vx rx -> Del (Node Black (balanceRight l k v (setRed lx)) kx vx rx) False
|
||||
_ -> boom "unreachable"
|
||||
|
||||
|
||||
|
||||
delMin = \t ->
|
||||
when t is
|
||||
Node Black Leaf k v r ->
|
||||
when r is
|
||||
Leaf -> Delmin (Del Leaf True) k v
|
||||
_ -> Delmin (Del (setBlack r) False) k v
|
||||
|
||||
Node Red Leaf k v r ->
|
||||
Delmin (Del r False) k v
|
||||
|
||||
Node c l k v r ->
|
||||
when delMin l is
|
||||
Delmin (Del lx True) kx vx -> Delmin (rebalanceRight c lx k v r) kx vx
|
||||
Delmin (Del lx False) kx vx -> Delmin (Del (Node c lx k v r) False) kx vx
|
||||
|
||||
Leaf ->
|
||||
Delmin (Del t False) 0 False
|
||||
|
||||
|
||||
|
||||
delete : Map, I64 -> Map
|
||||
delete = \t, k ->
|
||||
when del t k is
|
||||
Del tx _ -> setBlack tx
|
||||
|
||||
del = \t, k ->
|
||||
when t is
|
||||
Leaf -> Del Leaf False
|
||||
Node cx lx kx vx rx ->
|
||||
if (k < kx) then
|
||||
when (del lx k) is
|
||||
Del ly True -> rebalanceRight cx ly kx vx rx
|
||||
Del ly False -> Del (Node cx ly kx vx rx) False
|
||||
|
||||
else if (k > kx) then
|
||||
when (del rx k) is
|
||||
Del ry True -> rebalanceLeft cx lx kx vx ry
|
||||
Del ry False -> Del (Node cx lx kx vx ry) False
|
||||
|
||||
else
|
||||
when rx is
|
||||
Leaf -> if isBlack cx then makeBlack lx else Del lx False
|
||||
Node _ _ _ _ _ ->
|
||||
when delMin rx is
|
||||
Delmin (Del ry True) ky vy -> rebalanceLeft cx lx ky vy ry
|
||||
Delmin (Del ry False) ky vy -> Del (Node cx lx ky vy ry) False
|
106
examples/benchmarks/RBTreeInsert.roc
Normal file
106
examples/benchmarks/RBTreeInsert.roc
Normal file
|
@ -0,0 +1,106 @@
|
|||
app "rbtree-insert"
|
||||
packages { base: "platform" }
|
||||
imports [base.Task]
|
||||
provides [ main ] to base
|
||||
|
||||
main : Task.Task {} []
|
||||
main =
|
||||
tree : RedBlackTree I64 {}
|
||||
tree = insert 0 {} Empty
|
||||
|
||||
tree
|
||||
|> show
|
||||
|> Task.putLine
|
||||
|
||||
show : RedBlackTree I64 {} -> Str
|
||||
show = \tree -> showRBTree tree Str.fromInt (\{} -> "{}")
|
||||
|
||||
showRBTree : RedBlackTree k v, (k -> Str), (v -> Str) -> Str
|
||||
showRBTree = \tree, showKey, showValue ->
|
||||
when tree is
|
||||
Empty -> "Empty"
|
||||
Node color key value left right ->
|
||||
sColor = showColor color
|
||||
sKey = showKey key
|
||||
sValue = showValue value
|
||||
sL = nodeInParens left showKey showValue
|
||||
sR = nodeInParens right showKey showValue
|
||||
"Node \(sColor) \(sKey) \(sValue) \(sL) \(sR)"
|
||||
|
||||
nodeInParens : RedBlackTree k v, (k -> Str), (v -> Str) -> Str
|
||||
nodeInParens = \tree, showKey, showValue ->
|
||||
when tree is
|
||||
Empty -> showRBTree tree showKey showValue
|
||||
Node _ _ _ _ _ ->
|
||||
inner = showRBTree tree showKey showValue
|
||||
"(\(inner))"
|
||||
|
||||
showColor : NodeColor -> Str
|
||||
showColor = \color ->
|
||||
when color is
|
||||
Red -> "Red"
|
||||
Black -> "Black"
|
||||
|
||||
NodeColor : [ Red, Black ]
|
||||
|
||||
RedBlackTree k v : [ Node NodeColor k v (RedBlackTree k v) (RedBlackTree k v), Empty ]
|
||||
|
||||
Key k : Num k
|
||||
|
||||
insert : Key k, v, RedBlackTree (Key k) v -> RedBlackTree (Key k) v
|
||||
insert = \key, value, dict ->
|
||||
when insertHelp key value dict is
|
||||
Node Red k v l r ->
|
||||
Node Black k v l r
|
||||
|
||||
x ->
|
||||
x
|
||||
|
||||
insertHelp : (Key k), v, RedBlackTree (Key k) v -> RedBlackTree (Key k) v
|
||||
insertHelp = \key, value, dict ->
|
||||
when dict is
|
||||
Empty ->
|
||||
# New nodes are always red. If it violates the rules, it will be fixed
|
||||
# when balancing.
|
||||
Node Red key value Empty Empty
|
||||
|
||||
Node nColor nKey nValue nLeft nRight ->
|
||||
when Num.compare key nKey is
|
||||
LT ->
|
||||
balance nColor nKey nValue (insertHelp key value nLeft) nRight
|
||||
|
||||
EQ ->
|
||||
Node nColor nKey value nLeft nRight
|
||||
|
||||
GT ->
|
||||
balance nColor nKey nValue nLeft (insertHelp key value nRight)
|
||||
|
||||
balance : NodeColor, k, v, RedBlackTree k v, RedBlackTree k v -> RedBlackTree k v
|
||||
balance = \color, key, value, left, right ->
|
||||
when right is
|
||||
Node Red rK rV rLeft rRight ->
|
||||
when left is
|
||||
Node Red lK lV lLeft lRight ->
|
||||
Node
|
||||
Red
|
||||
key
|
||||
value
|
||||
(Node Black lK lV lLeft lRight)
|
||||
(Node Black rK rV rLeft rRight)
|
||||
|
||||
_ ->
|
||||
Node color rK rV (Node Red key value left rLeft) rRight
|
||||
|
||||
_ ->
|
||||
when left is
|
||||
Node Red lK lV (Node Red llK llV llLeft llRight) lRight ->
|
||||
Node
|
||||
Red
|
||||
lK
|
||||
lV
|
||||
(Node Black llK llV llLeft llRight)
|
||||
(Node Black key value lRight right)
|
||||
|
||||
_ ->
|
||||
Node color key value left right
|
||||
|
|
@ -88,13 +88,8 @@ fn call_the_closure(function_pointer: *const u8, closure_data_pointer: [*]u8) vo
|
|||
pub export fn roc_fx_putLine(rocPath: str.RocStr) i64 {
|
||||
const stdout = std.io.getStdOut().writer();
|
||||
|
||||
const u8_ptr = rocPath.asU8ptr();
|
||||
|
||||
var i: usize = 0;
|
||||
while (i < rocPath.len()) {
|
||||
stdout.print("{c}", .{u8_ptr[i]}) catch unreachable;
|
||||
|
||||
i += 1;
|
||||
for (rocPath.asSlice()) |char| {
|
||||
stdout.print("{c}", .{char}) catch unreachable;
|
||||
}
|
||||
|
||||
stdout.print("\n", .{}) catch unreachable;
|
||||
|
|
|
@ -260,6 +260,11 @@ pub const RocStr = extern struct {
|
|||
}
|
||||
};
|
||||
|
||||
// Str.equal
|
||||
pub fn strEqual(self: RocStr, other: RocStr) callconv(.C) bool {
|
||||
return self.eq(other);
|
||||
}
|
||||
|
||||
// Str.numberOfBytes
|
||||
pub fn strNumberOfBytes(string: RocStr) callconv(.C) usize {
|
||||
return string.len();
|
||||
|
@ -603,100 +608,8 @@ test "countSegments: delimiter interspered" {
|
|||
expectEqual(segments_count, 3);
|
||||
}
|
||||
|
||||
// Str.countGraphemeClusters
|
||||
const grapheme = @import("helpers/grapheme.zig");
|
||||
pub fn countGraphemeClusters(string: RocStr) callconv(.C) usize {
|
||||
if (string.isEmpty()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const bytes_len = string.len();
|
||||
const bytes_ptr = string.asU8ptr();
|
||||
|
||||
var bytes = bytes_ptr[0..bytes_len];
|
||||
var iter = (unicode.Utf8View.init(bytes) catch unreachable).iterator();
|
||||
|
||||
var count: usize = 0;
|
||||
var grapheme_break_state: ?grapheme.BoundClass = null;
|
||||
var grapheme_break_state_ptr = &grapheme_break_state;
|
||||
var opt_last_codepoint: ?u21 = null;
|
||||
while (iter.nextCodepoint()) |cur_codepoint| {
|
||||
if (opt_last_codepoint) |last_codepoint| {
|
||||
var did_break = grapheme.isGraphemeBreak(last_codepoint, cur_codepoint, grapheme_break_state_ptr);
|
||||
if (did_break) {
|
||||
count += 1;
|
||||
grapheme_break_state = null;
|
||||
}
|
||||
}
|
||||
opt_last_codepoint = cur_codepoint;
|
||||
}
|
||||
|
||||
// If there are no breaks, but the str is not empty, then there
|
||||
// must be a single grapheme
|
||||
if (bytes_len != 0) {
|
||||
count += 1;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
fn rocStrFromLiteral(bytes_arr: *const []u8) RocStr {}
|
||||
|
||||
test "countGraphemeClusters: empty string" {
|
||||
const count = countGraphemeClusters(RocStr.empty());
|
||||
expectEqual(count, 0);
|
||||
}
|
||||
|
||||
test "countGraphemeClusters: ascii characters" {
|
||||
const bytes_arr = "abcd";
|
||||
const bytes_len = bytes_arr.len;
|
||||
const str = RocStr.init(testing.allocator, bytes_arr, bytes_len);
|
||||
defer str.deinit(testing.allocator);
|
||||
|
||||
const count = countGraphemeClusters(str);
|
||||
expectEqual(count, 4);
|
||||
}
|
||||
|
||||
test "countGraphemeClusters: utf8 characters" {
|
||||
const bytes_arr = "ãxā";
|
||||
const bytes_len = bytes_arr.len;
|
||||
const str = RocStr.init(testing.allocator, bytes_arr, bytes_len);
|
||||
defer str.deinit(testing.allocator);
|
||||
|
||||
const count = countGraphemeClusters(str);
|
||||
expectEqual(count, 3);
|
||||
}
|
||||
|
||||
test "countGraphemeClusters: emojis" {
|
||||
const bytes_arr = "🤔🤔🤔";
|
||||
const bytes_len = bytes_arr.len;
|
||||
const str = RocStr.init(testing.allocator, bytes_arr, bytes_len);
|
||||
defer str.deinit(testing.allocator);
|
||||
|
||||
const count = countGraphemeClusters(str);
|
||||
expectEqual(count, 3);
|
||||
}
|
||||
|
||||
test "countGraphemeClusters: emojis and ut8 characters" {
|
||||
const bytes_arr = "🤔å🤔¥🤔ç";
|
||||
const bytes_len = bytes_arr.len;
|
||||
const str = RocStr.init(testing.allocator, bytes_arr, bytes_len);
|
||||
defer str.deinit(testing.allocator);
|
||||
|
||||
const count = countGraphemeClusters(str);
|
||||
expectEqual(count, 6);
|
||||
}
|
||||
|
||||
test "countGraphemeClusters: emojis, ut8, and ascii characters" {
|
||||
const bytes_arr = "6🤔å🤔e¥🤔çpp";
|
||||
const bytes_len = bytes_arr.len;
|
||||
const str = RocStr.init(testing.allocator, bytes_arr, bytes_len);
|
||||
defer str.deinit(testing.allocator);
|
||||
|
||||
const count = countGraphemeClusters(str);
|
||||
expectEqual(count, 10);
|
||||
}
|
||||
|
||||
// Str.startsWith
|
||||
pub fn startsWith(string: RocStr, prefix: RocStr) callconv(.C) bool {
|
||||
const bytes_len = string.len();
|
||||
|
@ -826,9 +739,7 @@ fn strConcatHelp(allocator: *Allocator, comptime T: type, result_in_place: InPla
|
|||
var result = RocStr.initBig(allocator, T, result_in_place, combined_length);
|
||||
|
||||
{
|
||||
const old_if_small = &@bitCast([16]u8, arg1);
|
||||
const old_if_big = @ptrCast([*]u8, arg1.str_bytes);
|
||||
const old_bytes = if (arg1.isSmallStr()) old_if_small else old_if_big;
|
||||
const old_bytes = arg1.asU8ptr();
|
||||
|
||||
const new_bytes: [*]u8 = @ptrCast([*]u8, result.str_bytes);
|
||||
|
||||
|
@ -836,9 +747,7 @@ fn strConcatHelp(allocator: *Allocator, comptime T: type, result_in_place: InPla
|
|||
}
|
||||
|
||||
{
|
||||
const old_if_small = &@bitCast([16]u8, arg2);
|
||||
const old_if_big = @ptrCast([*]u8, arg2.str_bytes);
|
||||
const old_bytes = if (arg2.isSmallStr()) old_if_small else old_if_big;
|
||||
const old_bytes = arg2.asU8ptr();
|
||||
|
||||
const new_bytes = @ptrCast([*]u8, result.str_bytes) + arg1.len();
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue