mirror of
https://github.com/roc-lang/roc.git
synced 2025-08-03 19:58:18 +00:00
Merge remote-tracking branch 'origin/trunk' into list-unreachable
This commit is contained in:
commit
762258ae20
58 changed files with 926 additions and 2075 deletions
|
@ -733,53 +733,6 @@ fn call_spec(
|
|||
add_loop(builder, block, state_type, init_state, loop_body)
|
||||
}
|
||||
|
||||
ListWalk { xs, state } | ListWalkBackwards { xs, state } => {
|
||||
let list = env.symbols[xs];
|
||||
let state = env.symbols[state];
|
||||
|
||||
let loop_body = |builder: &mut FuncDefBuilder, block, state| {
|
||||
let bag = builder.add_get_tuple_field(block, list, LIST_BAG_INDEX)?;
|
||||
|
||||
let element = builder.add_bag_get(block, bag)?;
|
||||
|
||||
let new_state = call_function!(builder, block, [state, element]);
|
||||
|
||||
Ok(new_state)
|
||||
};
|
||||
|
||||
let state_layout = argument_layouts[0];
|
||||
let state_type =
|
||||
layout_spec(builder, &state_layout, &WhenRecursive::Unreachable)?;
|
||||
let init_state = state;
|
||||
|
||||
add_loop(builder, block, state_type, init_state, loop_body)
|
||||
}
|
||||
ListWalkUntil { xs, state } => {
|
||||
let list = env.symbols[xs];
|
||||
let state = env.symbols[state];
|
||||
|
||||
let loop_body = |builder: &mut FuncDefBuilder, block, state| {
|
||||
let bag = builder.add_get_tuple_field(block, list, LIST_BAG_INDEX)?;
|
||||
|
||||
let element = builder.add_bag_get(block, bag)?;
|
||||
|
||||
let continue_or_stop = call_function!(builder, block, [state, element]);
|
||||
|
||||
// just assume it is a continue
|
||||
let unwrapped = builder.add_unwrap_union(block, continue_or_stop, 0)?;
|
||||
let new_state = builder.add_get_tuple_field(block, unwrapped, 0)?;
|
||||
|
||||
Ok(new_state)
|
||||
};
|
||||
|
||||
let state_layout = argument_layouts[0];
|
||||
let state_type =
|
||||
layout_spec(builder, &state_layout, &WhenRecursive::Unreachable)?;
|
||||
let init_state = state;
|
||||
|
||||
add_loop(builder, block, state_type, init_state, loop_body)
|
||||
}
|
||||
|
||||
// List.mapWithIndex : List before, (before, Nat -> after) -> List after
|
||||
ListMapWithIndex { xs } => {
|
||||
let list = env.symbols[xs];
|
||||
|
@ -963,82 +916,6 @@ fn call_spec(
|
|||
|
||||
add_loop(builder, block, state_type, init_state, loop_body)
|
||||
}
|
||||
ListAny { xs } => {
|
||||
let list = env.symbols[xs];
|
||||
|
||||
let loop_body = |builder: &mut FuncDefBuilder, block, _state| {
|
||||
let bag = builder.add_get_tuple_field(block, list, LIST_BAG_INDEX)?;
|
||||
let element = builder.add_bag_get(block, bag)?;
|
||||
|
||||
let new_state = call_function!(builder, block, [element]);
|
||||
|
||||
Ok(new_state)
|
||||
};
|
||||
|
||||
let state_layout = Layout::Builtin(Builtin::Bool);
|
||||
let state_type =
|
||||
layout_spec(builder, &state_layout, &WhenRecursive::Unreachable)?;
|
||||
|
||||
let init_state = new_num(builder, block)?;
|
||||
|
||||
add_loop(builder, block, state_type, init_state, loop_body)
|
||||
}
|
||||
ListAll { xs } => {
|
||||
let list = env.symbols[xs];
|
||||
|
||||
let loop_body = |builder: &mut FuncDefBuilder, block, _state| {
|
||||
let bag = builder.add_get_tuple_field(block, list, LIST_BAG_INDEX)?;
|
||||
let element = builder.add_bag_get(block, bag)?;
|
||||
|
||||
let new_state = call_function!(builder, block, [element]);
|
||||
|
||||
Ok(new_state)
|
||||
};
|
||||
|
||||
let state_layout = Layout::Builtin(Builtin::Bool);
|
||||
let state_type =
|
||||
layout_spec(builder, &state_layout, &WhenRecursive::Unreachable)?;
|
||||
|
||||
let init_state = new_num(builder, block)?;
|
||||
|
||||
add_loop(builder, block, state_type, init_state, loop_body)
|
||||
}
|
||||
ListFindUnsafe { xs } => {
|
||||
let list = env.symbols[xs];
|
||||
|
||||
// ListFindUnsafe returns { value: v, found: Bool=Int1 }
|
||||
let output_layouts = vec![argument_layouts[0], Layout::Builtin(Builtin::Bool)];
|
||||
let output_layout = Layout::struct_no_name_order(&output_layouts);
|
||||
let output_type =
|
||||
layout_spec(builder, &output_layout, &WhenRecursive::Unreachable)?;
|
||||
|
||||
let loop_body = |builder: &mut FuncDefBuilder, block, output| {
|
||||
let bag = builder.add_get_tuple_field(block, list, LIST_BAG_INDEX)?;
|
||||
let element = builder.add_bag_get(block, bag)?;
|
||||
let _is_found = call_function!(builder, block, [element]);
|
||||
|
||||
// We may or may not use the element we got from the list in the output struct,
|
||||
// depending on whether we found the element to satisfy the "find" predicate.
|
||||
// If we did find the element, our output "changes" to be a record including that element.
|
||||
let found_branch = builder.add_block();
|
||||
let new_output =
|
||||
builder.add_unknown_with(block, &[element], output_type)?;
|
||||
|
||||
let not_found_branch = builder.add_block();
|
||||
|
||||
builder.add_choice(
|
||||
block,
|
||||
&[
|
||||
BlockExpr(found_branch, new_output),
|
||||
BlockExpr(not_found_branch, output),
|
||||
],
|
||||
)
|
||||
};
|
||||
|
||||
// Assume the output is initially { found: False, value: \empty }
|
||||
let output_state = builder.add_unknown_with(block, &[], output_type)?;
|
||||
add_loop(builder, block, output_type, output_state, loop_body)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ const utils = @import("utils.zig");
|
|||
const RocResult = utils.RocResult;
|
||||
const UpdateMode = utils.UpdateMode;
|
||||
const mem = std.mem;
|
||||
const math = std.math;
|
||||
|
||||
const EqFn = fn (?[*]u8, ?[*]u8) callconv(.C) bool;
|
||||
const CompareFn = fn (?[*]u8, ?[*]u8, ?[*]u8) callconv(.C) u8;
|
||||
|
@ -30,6 +31,57 @@ pub const RocList = extern struct {
|
|||
return RocList{ .bytes = null, .length = 0, .capacity = 0 };
|
||||
}
|
||||
|
||||
pub fn eql(self: RocList, other: RocList) bool {
|
||||
if (self.len() != other.len()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Their lengths are the same, and one is empty; they're both empty!
|
||||
if (self.isEmpty()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
var index: usize = 0;
|
||||
const self_bytes = self.bytes orelse unreachable;
|
||||
const other_bytes = other.bytes orelse unreachable;
|
||||
|
||||
while (index < self.len()) {
|
||||
if (self_bytes[index] != other_bytes[index]) {
|
||||
return false;
|
||||
}
|
||||
|
||||
index += 1;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
pub fn fromSlice(comptime T: type, slice: []const T) RocList {
|
||||
if (slice.len == 0) {
|
||||
return RocList.empty();
|
||||
}
|
||||
|
||||
var list = allocate(@alignOf(T), slice.len, @sizeOf(T));
|
||||
|
||||
if (slice.len > 0) {
|
||||
const dest = list.bytes orelse unreachable;
|
||||
const src = @ptrCast([*]const u8, slice.ptr);
|
||||
const num_bytes = slice.len * @sizeOf(T);
|
||||
|
||||
@memcpy(dest, src, num_bytes);
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
pub fn deinit(self: RocList, comptime T: type) void {
|
||||
utils.decref(self.bytes, self.len(), @alignOf(T));
|
||||
}
|
||||
|
||||
pub fn elements(self: RocList, comptime T: type) ?[*]T {
|
||||
return @ptrCast(?[*]T, @alignCast(@alignOf(T), self.bytes));
|
||||
}
|
||||
|
||||
pub fn isUnique(self: RocList) bool {
|
||||
// the empty list is unique (in the sense that copying it will not leak memory)
|
||||
if (self.isEmpty()) {
|
||||
|
@ -145,44 +197,6 @@ const Caller2 = fn (?[*]u8, ?[*]u8, ?[*]u8, ?[*]u8) callconv(.C) void;
|
|||
const Caller3 = fn (?[*]u8, ?[*]u8, ?[*]u8, ?[*]u8, ?[*]u8) callconv(.C) void;
|
||||
const Caller4 = fn (?[*]u8, ?[*]u8, ?[*]u8, ?[*]u8, ?[*]u8, ?[*]u8) callconv(.C) void;
|
||||
|
||||
pub fn listReverse(list: RocList, alignment: u32, element_width: usize, update_mode: UpdateMode) callconv(.C) RocList {
|
||||
if (list.bytes) |source_ptr| {
|
||||
const size = list.len();
|
||||
|
||||
var i: usize = 0;
|
||||
const end: usize = size - 1;
|
||||
|
||||
if (update_mode == .InPlace or list.isUnique()) {
|
||||
|
||||
// Working from the front and back so
|
||||
// we only need to go ~(n / 2) iterations.
|
||||
// If the length is an odd number the middle
|
||||
// element stays in the same place anyways.
|
||||
while (i < (end - i)) : (i += 1) {
|
||||
swapElements(source_ptr, element_width, i, end - i);
|
||||
}
|
||||
|
||||
return list;
|
||||
} else {
|
||||
const output = RocList.allocate(alignment, size, element_width);
|
||||
|
||||
const target_ptr = output.bytes orelse unreachable;
|
||||
|
||||
while (i < size) : (i += 1) {
|
||||
const last_position = end - i;
|
||||
|
||||
@memcpy(target_ptr + (i * element_width), source_ptr + (last_position * element_width), element_width);
|
||||
}
|
||||
|
||||
utils.decref(list.bytes, size * element_width, alignment);
|
||||
|
||||
return output;
|
||||
}
|
||||
} else {
|
||||
return RocList.empty();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn listMap(
|
||||
list: RocList,
|
||||
caller: Caller1,
|
||||
|
@ -422,214 +436,6 @@ pub fn listMap4(
|
|||
}
|
||||
}
|
||||
|
||||
pub fn listWalk(
|
||||
list: RocList,
|
||||
caller: Caller2,
|
||||
data: Opaque,
|
||||
inc_n_data: IncN,
|
||||
data_is_owned: bool,
|
||||
accum: Opaque,
|
||||
alignment: u32,
|
||||
element_width: usize,
|
||||
accum_width: usize,
|
||||
output: Opaque,
|
||||
) callconv(.C) void {
|
||||
if (accum_width == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (list.isEmpty()) {
|
||||
@memcpy(output orelse unreachable, accum orelse unreachable, accum_width);
|
||||
return;
|
||||
}
|
||||
|
||||
if (data_is_owned) {
|
||||
inc_n_data(data, list.len());
|
||||
}
|
||||
|
||||
// TODO handle alloc failing!
|
||||
const bytes_ptr: [*]u8 = utils.alloc(accum_width, alignment) orelse unreachable;
|
||||
var b1 = output orelse unreachable;
|
||||
var b2 = bytes_ptr;
|
||||
|
||||
@memcpy(b2, accum orelse unreachable, accum_width);
|
||||
|
||||
if (list.bytes) |source_ptr| {
|
||||
var i: usize = 0;
|
||||
const size = list.len();
|
||||
while (i < size) : (i += 1) {
|
||||
const element = source_ptr + i * element_width;
|
||||
caller(data, b2, element, b1);
|
||||
|
||||
std.mem.swap([*]u8, &b1, &b2);
|
||||
}
|
||||
}
|
||||
|
||||
@memcpy(output orelse unreachable, b2, accum_width);
|
||||
utils.dealloc(bytes_ptr, alignment);
|
||||
}
|
||||
|
||||
pub fn listWalkBackwards(
|
||||
list: RocList,
|
||||
caller: Caller2,
|
||||
data: Opaque,
|
||||
inc_n_data: IncN,
|
||||
data_is_owned: bool,
|
||||
accum: Opaque,
|
||||
alignment: u32,
|
||||
element_width: usize,
|
||||
accum_width: usize,
|
||||
output: Opaque,
|
||||
) callconv(.C) void {
|
||||
if (accum_width == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (list.isEmpty()) {
|
||||
@memcpy(output orelse unreachable, accum orelse unreachable, accum_width);
|
||||
return;
|
||||
}
|
||||
|
||||
if (data_is_owned) {
|
||||
inc_n_data(data, list.len());
|
||||
}
|
||||
|
||||
// TODO handle alloc failing!
|
||||
const bytes_ptr: [*]u8 = utils.alloc(accum_width, alignment) orelse unreachable;
|
||||
var b1 = output orelse unreachable;
|
||||
var b2 = bytes_ptr;
|
||||
|
||||
@memcpy(b2, accum orelse unreachable, accum_width);
|
||||
|
||||
if (list.bytes) |source_ptr| {
|
||||
const size = list.len();
|
||||
var i: usize = size;
|
||||
while (i > 0) {
|
||||
i -= 1;
|
||||
const element = source_ptr + i * element_width;
|
||||
caller(data, b2, element, b1);
|
||||
|
||||
std.mem.swap([*]u8, &b1, &b2);
|
||||
}
|
||||
}
|
||||
|
||||
@memcpy(output orelse unreachable, b2, accum_width);
|
||||
utils.dealloc(bytes_ptr, alignment);
|
||||
}
|
||||
|
||||
pub fn listWalkUntil(
|
||||
list: RocList,
|
||||
caller: Caller2,
|
||||
data: Opaque,
|
||||
inc_n_data: IncN,
|
||||
data_is_owned: bool,
|
||||
accum: Opaque,
|
||||
alignment: u32,
|
||||
element_width: usize,
|
||||
continue_stop_width: usize,
|
||||
accum_width: usize,
|
||||
has_tag_id: HasTagId,
|
||||
dec: Dec,
|
||||
output: Opaque,
|
||||
) callconv(.C) void {
|
||||
// [Continue a, Stop a]
|
||||
|
||||
if (accum_width == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (list.isEmpty()) {
|
||||
@memcpy(output orelse unreachable, accum orelse unreachable, accum_width);
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO handle alloc failing!
|
||||
const bytes_ptr: [*]u8 = utils.alloc(continue_stop_width, alignment) orelse unreachable;
|
||||
|
||||
// NOTE: assumes data bytes are the first bytes in a tag
|
||||
@memcpy(bytes_ptr, accum orelse unreachable, accum_width);
|
||||
|
||||
if (list.bytes) |source_ptr| {
|
||||
var i: usize = 0;
|
||||
const size = list.len();
|
||||
while (i < size) : (i += 1) {
|
||||
const element = source_ptr + i * element_width;
|
||||
|
||||
if (data_is_owned) {
|
||||
inc_n_data(data, 1);
|
||||
}
|
||||
|
||||
caller(data, bytes_ptr, element, bytes_ptr);
|
||||
|
||||
// [Continue ..., Stop]
|
||||
const tag_id = has_tag_id(0, bytes_ptr);
|
||||
|
||||
if (!tag_id.matched) {
|
||||
// decrement refcount of the remaining items
|
||||
i += 1;
|
||||
while (i < size) : (i += 1) {
|
||||
dec(source_ptr + i * element_width);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@memcpy(output orelse unreachable, bytes_ptr, accum_width);
|
||||
utils.dealloc(bytes_ptr, alignment);
|
||||
}
|
||||
|
||||
// List.contains : List k, k -> Bool
|
||||
pub fn listContains(list: RocList, key: Opaque, key_width: usize, is_eq: EqFn) callconv(.C) bool {
|
||||
if (list.bytes) |source_ptr| {
|
||||
const size = list.len();
|
||||
var i: usize = 0;
|
||||
while (i < size) : (i += 1) {
|
||||
const element = source_ptr + i * key_width;
|
||||
if (is_eq(element, key)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
pub fn listRepeat(count: usize, alignment: u32, element: Opaque, element_width: usize, inc_n_element: IncN) callconv(.C) RocList {
|
||||
if (count == 0) {
|
||||
return RocList.empty();
|
||||
}
|
||||
|
||||
var output = RocList.allocate(alignment, count, element_width);
|
||||
|
||||
if (output.bytes) |target_ptr| {
|
||||
// increment the element's RC N times
|
||||
inc_n_element(element, count);
|
||||
|
||||
var i: usize = 0;
|
||||
const source = element orelse unreachable;
|
||||
while (i < count) : (i += 1) {
|
||||
@memcpy(target_ptr + i * element_width, source, element_width);
|
||||
}
|
||||
|
||||
return output;
|
||||
} else {
|
||||
unreachable;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn listSingle(alignment: u32, element: Opaque, element_width: usize) callconv(.C) RocList {
|
||||
var output = RocList.allocate(alignment, 1, element_width);
|
||||
|
||||
if (output.bytes) |target| {
|
||||
if (element) |source| {
|
||||
@memcpy(target, source, element_width);
|
||||
}
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
pub fn listWithCapacity(capacity: usize, alignment: u32, element_width: usize) callconv(.C) RocList {
|
||||
var output = RocList.allocate(alignment, capacity, element_width);
|
||||
output.length = 0;
|
||||
|
@ -882,66 +688,6 @@ pub fn listSortWith(
|
|||
return list;
|
||||
}
|
||||
|
||||
pub fn listAny(
|
||||
list: RocList,
|
||||
caller: Caller1,
|
||||
data: Opaque,
|
||||
inc_n_data: IncN,
|
||||
data_is_owned: bool,
|
||||
element_width: usize,
|
||||
) callconv(.C) bool {
|
||||
if (list.bytes) |source_ptr| {
|
||||
const size = list.len();
|
||||
|
||||
if (data_is_owned) {
|
||||
inc_n_data(data, size);
|
||||
}
|
||||
|
||||
var i: usize = 0;
|
||||
var satisfied = false;
|
||||
while (i < size) : (i += 1) {
|
||||
const element = source_ptr + i * element_width;
|
||||
caller(data, element, @ptrCast(?[*]u8, &satisfied));
|
||||
|
||||
if (satisfied) {
|
||||
return satisfied;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
pub fn listAll(
|
||||
list: RocList,
|
||||
caller: Caller1,
|
||||
data: Opaque,
|
||||
inc_n_data: IncN,
|
||||
data_is_owned: bool,
|
||||
element_width: usize,
|
||||
) callconv(.C) bool {
|
||||
if (list.bytes) |source_ptr| {
|
||||
const size = list.len();
|
||||
|
||||
if (data_is_owned) {
|
||||
inc_n_data(data, size);
|
||||
}
|
||||
|
||||
var i: usize = 0;
|
||||
while (i < size) : (i += 1) {
|
||||
var satisfied = false;
|
||||
const element = source_ptr + i * element_width;
|
||||
caller(data, element, @ptrCast(?[*]u8, &satisfied));
|
||||
|
||||
if (!satisfied) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// SWAP ELEMENTS
|
||||
|
||||
inline fn swapHelp(width: usize, temporary: [*]u8, ptr1: [*]u8, ptr2: [*]u8) void {
|
||||
|
@ -1075,41 +821,6 @@ inline fn listReplaceInPlaceHelp(
|
|||
return list;
|
||||
}
|
||||
|
||||
pub fn listFindUnsafe(
|
||||
list: RocList,
|
||||
caller: Caller1,
|
||||
data: Opaque,
|
||||
inc_n_data: IncN,
|
||||
data_is_owned: bool,
|
||||
element_width: usize,
|
||||
inc: Inc,
|
||||
dec: Dec,
|
||||
) callconv(.C) extern struct { value: Opaque, found: bool } {
|
||||
if (list.bytes) |source_ptr| {
|
||||
const size = list.len();
|
||||
if (data_is_owned) {
|
||||
inc_n_data(data, size);
|
||||
}
|
||||
|
||||
var i: usize = 0;
|
||||
while (i < size) : (i += 1) {
|
||||
var theOne = false;
|
||||
const element = source_ptr + (i * element_width);
|
||||
inc(element);
|
||||
caller(data, element, @ptrCast(?[*]u8, &theOne));
|
||||
|
||||
if (theOne) {
|
||||
return .{ .value = element, .found = true };
|
||||
} else {
|
||||
dec(element);
|
||||
}
|
||||
}
|
||||
return .{ .value = null, .found = false };
|
||||
} else {
|
||||
return .{ .value = null, .found = false };
|
||||
}
|
||||
}
|
||||
|
||||
pub fn listIsUnique(
|
||||
list: RocList,
|
||||
) callconv(.C) bool {
|
||||
|
|
|
@ -41,16 +41,9 @@ comptime {
|
|||
exportListFn(list.listMap3, "map3");
|
||||
exportListFn(list.listMap4, "map4");
|
||||
exportListFn(list.listMapWithIndex, "map_with_index");
|
||||
exportListFn(list.listWalk, "walk");
|
||||
exportListFn(list.listWalkUntil, "walkUntil");
|
||||
exportListFn(list.listWalkBackwards, "walk_backwards");
|
||||
exportListFn(list.listContains, "contains");
|
||||
exportListFn(list.listRepeat, "repeat");
|
||||
exportListFn(list.listAppend, "append");
|
||||
exportListFn(list.listPrepend, "prepend");
|
||||
exportListFn(list.listSingle, "single");
|
||||
exportListFn(list.listWithCapacity, "with_capacity");
|
||||
exportListFn(list.listReverse, "reverse");
|
||||
exportListFn(list.listSortWith, "sort_with");
|
||||
exportListFn(list.listConcat, "concat");
|
||||
exportListFn(list.listSublist, "sublist");
|
||||
|
@ -58,9 +51,6 @@ comptime {
|
|||
exportListFn(list.listReplace, "replace");
|
||||
exportListFn(list.listReplaceInPlace, "replace_in_place");
|
||||
exportListFn(list.listSwap, "swap");
|
||||
exportListFn(list.listAny, "any");
|
||||
exportListFn(list.listAll, "all");
|
||||
exportListFn(list.listFindUnsafe, "find_unsafe");
|
||||
exportListFn(list.listIsUnique, "is_unique");
|
||||
}
|
||||
|
||||
|
@ -152,11 +142,12 @@ comptime {
|
|||
const str = @import("str.zig");
|
||||
comptime {
|
||||
exportStrFn(str.init, "init");
|
||||
exportStrFn(str.strToScalarsC, "to_scalars");
|
||||
exportStrFn(str.strSplitInPlaceC, "str_split_in_place");
|
||||
exportStrFn(str.countSegments, "count_segments");
|
||||
exportStrFn(str.countGraphemeClusters, "count_grapheme_clusters");
|
||||
exportStrFn(str.startsWith, "starts_with");
|
||||
exportStrFn(str.startsWithCodePt, "starts_with_code_point");
|
||||
exportStrFn(str.startsWithScalar, "starts_with_scalar");
|
||||
exportStrFn(str.endsWith, "ends_with");
|
||||
exportStrFn(str.strConcatC, "concat");
|
||||
exportStrFn(str.strJoinWithC, "joinWith");
|
||||
|
|
|
@ -56,6 +56,10 @@ pub const RocStr = extern struct {
|
|||
return result;
|
||||
}
|
||||
|
||||
pub fn fromSlice(slice: []const u8) RocStr {
|
||||
return RocStr.init(slice.ptr, slice.len);
|
||||
}
|
||||
|
||||
pub fn initBig(_: InPlace, number_of_chars: usize) RocStr {
|
||||
const first_element = utils.allocateWithRefcount(number_of_chars, @sizeOf(usize));
|
||||
|
||||
|
@ -227,6 +231,17 @@ pub const RocStr = extern struct {
|
|||
return self.str_capacity ^ MASK;
|
||||
}
|
||||
|
||||
// This does a small string check, but no bounds checking whatsoever!
|
||||
pub fn getUnchecked(self: RocStr, index: usize) u8 {
|
||||
if (self.isSmallStr()) {
|
||||
return self.asArray()[index];
|
||||
} else {
|
||||
const bytes = self.str_bytes orelse unreachable;
|
||||
|
||||
return bytes[index];
|
||||
}
|
||||
}
|
||||
|
||||
pub fn isEmpty(self: RocStr) bool {
|
||||
return self.len() == 0;
|
||||
}
|
||||
|
@ -239,7 +254,7 @@ pub const RocStr = extern struct {
|
|||
const length = self.len();
|
||||
const longest_small_str = @sizeOf(RocStr) - 1;
|
||||
|
||||
// NOTE: We want to compare length here, *NOT* check for is_small_str!
|
||||
// NOTE: We want to compare length here, *NOT* check for isSmallStr!
|
||||
// This is because we explicitly want the empty string to be handled in
|
||||
// this branch, even though the empty string is not a small string.
|
||||
//
|
||||
|
@ -452,6 +467,242 @@ pub fn strNumberOfBytes(string: RocStr) callconv(.C) usize {
|
|||
return string.len();
|
||||
}
|
||||
|
||||
// Str.toScalars
|
||||
pub fn strToScalarsC(str: RocStr) callconv(.C) RocList {
|
||||
return @call(.{ .modifier = always_inline }, strToScalars, .{str});
|
||||
}
|
||||
|
||||
fn strToScalars(string: RocStr) callconv(.C) RocList {
|
||||
const str_len = string.len();
|
||||
|
||||
if (str_len == 0) {
|
||||
return RocList.empty();
|
||||
}
|
||||
|
||||
var capacity = str_len;
|
||||
|
||||
if (!string.isSmallStr()) {
|
||||
capacity = string.capacity();
|
||||
}
|
||||
|
||||
// For purposes of preallocation, assume the number of code points is the same
|
||||
// as the number of bytes. This might be longer than necessary, but definitely
|
||||
// should not require a second allocation.
|
||||
var answer = RocList.allocate(@alignOf(u32), capacity, @sizeOf(u32));
|
||||
|
||||
// `orelse unreachable` is fine here, because we already did an early
|
||||
// return to verify the string was nonempty.
|
||||
var answer_elems = answer.elements(u32) orelse unreachable;
|
||||
var src_index: usize = 0;
|
||||
var answer_index: usize = 0;
|
||||
|
||||
while (src_index < str_len) {
|
||||
src_index += writeNextScalar(string, src_index, answer_elems, answer_index);
|
||||
answer_index += 1;
|
||||
}
|
||||
|
||||
answer.length = answer_index;
|
||||
|
||||
return answer;
|
||||
}
|
||||
|
||||
// Given a non-empty RocStr, and a src_index byte index into that string,
|
||||
// and a destination [*]u32, and an index into that destination,
|
||||
// Parses the next scalar value out of the string (at the given byte index),
|
||||
// writes it into the destination, and returns the number of bytes parsed.
|
||||
inline fn writeNextScalar(non_empty_string: RocStr, src_index: usize, dest: [*]u32, dest_index: usize) usize {
|
||||
const utf8_byte = non_empty_string.getUnchecked(src_index);
|
||||
|
||||
// How UTF-8 bytes work:
|
||||
// https://docs.teradata.com/r/Teradata-Database-International-Character-Set-Support/June-2017/Client-Character-Set-Options/UTF8-Client-Character-Set-Support/UTF8-Multibyte-Sequences
|
||||
if (utf8_byte <= 127) {
|
||||
// It's an ASCII character. Copy it over directly.
|
||||
dest[dest_index] = @intCast(u32, utf8_byte);
|
||||
|
||||
return 1;
|
||||
} else if (utf8_byte >> 5 == 0b0000_0110) {
|
||||
// Its three high order bits are 110, so this is a two-byte sequence.
|
||||
|
||||
// Example:
|
||||
// utf-8: 1100 1111 1011 0001
|
||||
// code pt: 0000 0011 1111 0001 (decimal: 1009)
|
||||
|
||||
// Discard the first byte's high order bits of 110.
|
||||
var code_pt = @intCast(u32, utf8_byte & 0b0001_1111);
|
||||
|
||||
// Discard the second byte's high order bits of 10.
|
||||
code_pt <<= 6;
|
||||
code_pt |= non_empty_string.getUnchecked(src_index + 1) & 0b0011_1111;
|
||||
|
||||
dest[dest_index] = code_pt;
|
||||
|
||||
return 2;
|
||||
} else if (utf8_byte >> 4 == 0b0000_1110) {
|
||||
// Its four high order bits are 1110, so this is a three-byte sequence.
|
||||
|
||||
// Discard the first byte's high order bits of 1110.
|
||||
var code_pt = @intCast(u32, utf8_byte & 0b0000_1111);
|
||||
|
||||
// Discard the second byte's high order bits of 10.
|
||||
code_pt <<= 6;
|
||||
code_pt |= non_empty_string.getUnchecked(src_index + 1) & 0b0011_1111;
|
||||
|
||||
// Discard the third byte's high order bits of 10 (same as second byte).
|
||||
code_pt <<= 6;
|
||||
code_pt |= non_empty_string.getUnchecked(src_index + 2) & 0b0011_1111;
|
||||
|
||||
dest[dest_index] = code_pt;
|
||||
|
||||
return 3;
|
||||
} else {
|
||||
// This must be a four-byte sequence, so the five high order bits should be 11110.
|
||||
|
||||
// Discard the first byte's high order bits of 11110.
|
||||
var code_pt = @intCast(u32, utf8_byte & 0b0000_0111);
|
||||
|
||||
// Discard the second byte's high order bits of 10.
|
||||
code_pt <<= 6;
|
||||
code_pt |= non_empty_string.getUnchecked(src_index + 1) & 0b0011_1111;
|
||||
|
||||
// Discard the third byte's high order bits of 10 (same as second byte).
|
||||
code_pt <<= 6;
|
||||
code_pt |= non_empty_string.getUnchecked(src_index + 2) & 0b0011_1111;
|
||||
|
||||
// Discard the fourth byte's high order bits of 10 (same as second and third).
|
||||
code_pt <<= 6;
|
||||
code_pt |= non_empty_string.getUnchecked(src_index + 3) & 0b0011_1111;
|
||||
|
||||
dest[dest_index] = code_pt;
|
||||
|
||||
return 4;
|
||||
}
|
||||
}
|
||||
|
||||
test "strToScalars: empty string" {
|
||||
const str = RocStr.fromSlice("");
|
||||
defer RocStr.deinit(str);
|
||||
|
||||
const expected = RocList.empty();
|
||||
const actual = strToScalars(str);
|
||||
defer RocList.deinit(actual, u32);
|
||||
|
||||
try expect(RocList.eql(actual, expected));
|
||||
}
|
||||
|
||||
test "strToScalars: One ASCII char" {
|
||||
const str = RocStr.fromSlice("R");
|
||||
defer RocStr.deinit(str);
|
||||
|
||||
const expected_array = [_]u32{82};
|
||||
const expected = RocList.fromSlice(u32, expected_array[0..expected_array.len]);
|
||||
defer RocList.deinit(expected, u32);
|
||||
|
||||
const actual = strToScalars(str);
|
||||
defer RocList.deinit(actual, u32);
|
||||
|
||||
try expect(RocList.eql(actual, expected));
|
||||
}
|
||||
|
||||
test "strToScalars: Multiple ASCII chars" {
|
||||
const str = RocStr.fromSlice("Roc!");
|
||||
defer RocStr.deinit(str);
|
||||
|
||||
const expected_array = [_]u32{ 82, 111, 99, 33 };
|
||||
const expected = RocList.fromSlice(u32, expected_array[0..expected_array.len]);
|
||||
defer RocList.deinit(expected, u32);
|
||||
|
||||
const actual = strToScalars(str);
|
||||
defer RocList.deinit(actual, u32);
|
||||
|
||||
try expect(RocList.eql(actual, expected));
|
||||
}
|
||||
|
||||
test "strToScalars: One 2-byte UTF-8 character" {
|
||||
const str = RocStr.fromSlice("é");
|
||||
defer RocStr.deinit(str);
|
||||
|
||||
const expected_array = [_]u32{233};
|
||||
const expected = RocList.fromSlice(u32, expected_array[0..expected_array.len]);
|
||||
defer RocList.deinit(expected, u32);
|
||||
|
||||
const actual = strToScalars(str);
|
||||
defer RocList.deinit(actual, u32);
|
||||
|
||||
try expect(RocList.eql(actual, expected));
|
||||
}
|
||||
|
||||
test "strToScalars: Multiple 2-byte UTF-8 characters" {
|
||||
const str = RocStr.fromSlice("Cäfés");
|
||||
defer RocStr.deinit(str);
|
||||
|
||||
const expected_array = [_]u32{ 67, 228, 102, 233, 115 };
|
||||
const expected = RocList.fromSlice(u32, expected_array[0..expected_array.len]);
|
||||
defer RocList.deinit(expected, u32);
|
||||
|
||||
const actual = strToScalars(str);
|
||||
defer RocList.deinit(actual, u32);
|
||||
|
||||
try expect(RocList.eql(actual, expected));
|
||||
}
|
||||
|
||||
test "strToScalars: One 3-byte UTF-8 character" {
|
||||
const str = RocStr.fromSlice("鹏");
|
||||
defer RocStr.deinit(str);
|
||||
|
||||
const expected_array = [_]u32{40527};
|
||||
const expected = RocList.fromSlice(u32, expected_array[0..expected_array.len]);
|
||||
defer RocList.deinit(expected, u32);
|
||||
|
||||
const actual = strToScalars(str);
|
||||
defer RocList.deinit(actual, u32);
|
||||
|
||||
try expect(RocList.eql(actual, expected));
|
||||
}
|
||||
|
||||
test "strToScalars: Multiple 3-byte UTF-8 characters" {
|
||||
const str = RocStr.fromSlice("鹏很有趣");
|
||||
defer RocStr.deinit(str);
|
||||
|
||||
const expected_array = [_]u32{ 40527, 24456, 26377, 36259 };
|
||||
const expected = RocList.fromSlice(u32, expected_array[0..expected_array.len]);
|
||||
defer RocList.deinit(expected, u32);
|
||||
|
||||
const actual = strToScalars(str);
|
||||
defer RocList.deinit(actual, u32);
|
||||
|
||||
try expect(RocList.eql(actual, expected));
|
||||
}
|
||||
|
||||
test "strToScalars: One 4-byte UTF-8 character" {
|
||||
// from https://design215.com/toolbox/utf8-4byte-characters.php
|
||||
const str = RocStr.fromSlice("𒀀");
|
||||
defer RocStr.deinit(str);
|
||||
|
||||
const expected_array = [_]u32{73728};
|
||||
const expected = RocList.fromSlice(u32, expected_array[0..expected_array.len]);
|
||||
defer RocList.deinit(expected, u32);
|
||||
|
||||
const actual = strToScalars(str);
|
||||
defer RocList.deinit(actual, u32);
|
||||
|
||||
try expect(RocList.eql(actual, expected));
|
||||
}
|
||||
|
||||
test "strToScalars: Multiple 4-byte UTF-8 characters" {
|
||||
// from https://design215.com/toolbox/utf8-4byte-characters.php
|
||||
const str = RocStr.fromSlice("𒀀𒀁");
|
||||
defer RocStr.deinit(str);
|
||||
|
||||
const expected_array = [_]u32{ 73728, 73729 };
|
||||
const expected = RocList.fromSlice(u32, expected_array[0..expected_array.len]);
|
||||
defer RocList.deinit(expected, u32);
|
||||
|
||||
const actual = strToScalars(str);
|
||||
defer RocList.deinit(actual, u32);
|
||||
|
||||
try expect(RocList.eql(actual, expected));
|
||||
}
|
||||
|
||||
// Str.fromInt
|
||||
pub fn exportFromInt(comptime T: type, comptime name: []const u8) void {
|
||||
comptime var f = struct {
|
||||
|
@ -972,56 +1223,60 @@ pub fn repeat(string: RocStr, count: usize) callconv(.C) RocStr {
|
|||
return ret_string;
|
||||
}
|
||||
|
||||
// Str.startsWithCodePt
|
||||
pub fn startsWithCodePt(string: RocStr, prefix: u32) callconv(.C) bool {
|
||||
const bytes_ptr = string.asU8ptr();
|
||||
// Str.startsWithScalar
|
||||
pub fn startsWithScalar(string: RocStr, prefix: u32) callconv(.C) bool {
|
||||
const str_len = string.len();
|
||||
|
||||
var buffer: [4]u8 = undefined;
|
||||
|
||||
var width = std.unicode.utf8Encode(@truncate(u21, prefix), &buffer) catch unreachable;
|
||||
|
||||
var i: usize = 0;
|
||||
while (i < width) : (i += 1) {
|
||||
const a = buffer[i];
|
||||
const b = bytes_ptr[i];
|
||||
if (a != b) {
|
||||
return false;
|
||||
}
|
||||
if (str_len == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
// Write this (non-empty) string's first scalar into `first_scalar`
|
||||
var first_scalar: [1]u32 = undefined;
|
||||
|
||||
_ = writeNextScalar(string, 0, &first_scalar, 0);
|
||||
|
||||
// Return whether `first_scalar` equals `prefix`
|
||||
return @ptrCast(*u32, &first_scalar).* == prefix;
|
||||
}
|
||||
|
||||
test "startsWithCodePt: ascii char" {
|
||||
const whole = RocStr.init("foobar", 6);
|
||||
const prefix = 'f';
|
||||
try expect(startsWithCodePt(whole, prefix));
|
||||
test "startsWithScalar: empty string" {
|
||||
const whole = RocStr.empty();
|
||||
const prefix: u32 = 'x';
|
||||
try expect(!startsWithScalar(whole, prefix));
|
||||
}
|
||||
|
||||
test "startsWithCodePt: emoji" {
|
||||
const yes = RocStr.init("💖foobar", 10);
|
||||
const no = RocStr.init("foobar", 6);
|
||||
const prefix = '💖';
|
||||
try expect(startsWithCodePt(yes, prefix));
|
||||
try expect(!startsWithCodePt(no, prefix));
|
||||
test "startsWithScalar: ascii char" {
|
||||
const whole = RocStr.fromSlice("foobar");
|
||||
const prefix: u32 = 'f';
|
||||
try expect(startsWithScalar(whole, prefix));
|
||||
}
|
||||
|
||||
test "startsWithScalar: emoji" {
|
||||
const yes = RocStr.fromSlice("💖foobar");
|
||||
const no = RocStr.fromSlice("foobar");
|
||||
const prefix: u32 = '💖';
|
||||
|
||||
try expect(startsWithScalar(yes, prefix));
|
||||
try expect(!startsWithScalar(no, prefix));
|
||||
}
|
||||
|
||||
test "startsWith: foo starts with fo" {
|
||||
const foo = RocStr.init("foo", 3);
|
||||
const fo = RocStr.init("fo", 2);
|
||||
const foo = RocStr.fromSlice("foo");
|
||||
const fo = RocStr.fromSlice("fo");
|
||||
try expect(startsWith(foo, fo));
|
||||
}
|
||||
|
||||
test "startsWith: 123456789123456789 starts with 123456789123456789" {
|
||||
const str = RocStr.init("123456789123456789", 18);
|
||||
const str = RocStr.fromSlice("123456789123456789");
|
||||
defer str.deinit();
|
||||
try expect(startsWith(str, str));
|
||||
}
|
||||
|
||||
test "startsWith: 12345678912345678910 starts with 123456789123456789" {
|
||||
const str = RocStr.init("12345678912345678910", 20);
|
||||
const str = RocStr.fromSlice("12345678912345678910");
|
||||
defer str.deinit();
|
||||
const prefix = RocStr.init("123456789123456789", 18);
|
||||
const prefix = RocStr.fromSlice("123456789123456789");
|
||||
defer prefix.deinit();
|
||||
|
||||
try expect(startsWith(str, prefix));
|
||||
|
|
|
@ -183,7 +183,7 @@ pub fn decref(
|
|||
|
||||
var bytes = bytes_or_null orelse return;
|
||||
|
||||
const isizes: [*]isize = @ptrCast([*]isize, @alignCast(@sizeOf(isize), bytes));
|
||||
const isizes: [*]isize = @ptrCast([*]isize, @alignCast(@alignOf(isize), bytes));
|
||||
|
||||
decref_ptr_to_refcount(isizes - 1, alignment);
|
||||
}
|
||||
|
|
|
@ -372,10 +372,35 @@ contains = \list, needle ->
|
|||
## Note that in other languages, `walk` is sometimes called `reduce`,
|
||||
## `fold`, `foldLeft`, or `foldl`.
|
||||
walk : List elem, state, (state, elem -> state) -> state
|
||||
walk = \list, state, func ->
|
||||
walkHelp list state func 0 (len list)
|
||||
|
||||
## internal helper
|
||||
walkHelp : List elem, state, (state, elem -> state), Nat, Nat -> state
|
||||
walkHelp = \list, state, f, index, length ->
|
||||
if index < length then
|
||||
nextState = f state (getUnsafe list index)
|
||||
|
||||
walkHelp list nextState f (index + 1) length
|
||||
else
|
||||
state
|
||||
|
||||
## Note that in other languages, `walkBackwards` is sometimes called `reduceRight`,
|
||||
## `fold`, `foldRight`, or `foldr`.
|
||||
walkBackwards : List elem, state, (state, elem -> state) -> state
|
||||
walkBackwards = \list, state, func ->
|
||||
walkBackwardsHelp list state func (len list)
|
||||
|
||||
## internal helper
|
||||
walkBackwardsHelp : List elem, state, (state, elem -> state), Nat -> state
|
||||
walkBackwardsHelp = \list, state, f, indexPlusOne ->
|
||||
if indexPlusOne == 0 then
|
||||
state
|
||||
else
|
||||
index = indexPlusOne - 1
|
||||
nextState = f state (getUnsafe list index)
|
||||
|
||||
walkBackwardsHelp list nextState f index
|
||||
|
||||
## Same as [List.walk], except you can stop walking early.
|
||||
##
|
||||
|
@ -387,7 +412,7 @@ walkBackwards : List elem, state, (state, elem -> state) -> state
|
|||
## be outweighed if it results in skipping even a small number of elements.
|
||||
##
|
||||
## As such, it is typically better for performance to use this over [List.walk]
|
||||
## if returning `Done` earlier than the last element is expected to be common.
|
||||
## if returning `Break` earlier than the last element is expected to be common.
|
||||
walkUntil : List elem, state, (state, elem -> [Continue state, Break state]) -> state
|
||||
walkUntil = \list, initial, step ->
|
||||
when List.iterate list initial step is
|
||||
|
@ -763,7 +788,16 @@ findIndex = \list, matcher ->
|
|||
##
|
||||
## Some languages have a function called **`slice`** which works similarly to this.
|
||||
sublist : List elem, { start : Nat, len : Nat } -> List elem
|
||||
|
||||
## Intersperses `sep` between the elements of `list`
|
||||
## >>> List.intersperse 9 [1, 2, 3] # [1, 9, 2, 9, 3]
|
||||
intersperse : List elem, elem -> List elem
|
||||
intersperse = \list, sep ->
|
||||
capacity = 2 * List.len list
|
||||
init = List.withCapacity capacity
|
||||
newList = List.walk list init (\acc, elem -> acc |> List.append elem |> List.append sep)
|
||||
|
||||
List.dropLast newList
|
||||
|
||||
## Splits the list into two lists, around the given index.
|
||||
##
|
||||
|
|
|
@ -1,15 +1,15 @@
|
|||
interface Str
|
||||
exposes
|
||||
[
|
||||
concat,
|
||||
Utf8Problem,
|
||||
Utf8ByteProblem,
|
||||
concat,
|
||||
isEmpty,
|
||||
joinWith,
|
||||
split,
|
||||
repeat,
|
||||
countGraphemes,
|
||||
startsWithCodePt,
|
||||
startsWithScalar,
|
||||
toUtf8,
|
||||
fromUtf8,
|
||||
fromUtf8Range,
|
||||
|
@ -32,6 +32,7 @@ interface Str
|
|||
toI16,
|
||||
toU8,
|
||||
toI8,
|
||||
toScalars,
|
||||
]
|
||||
imports [Bool.{ Bool }, Result.{ Result }]
|
||||
|
||||
|
@ -164,13 +165,20 @@ countGraphemes : Str -> Nat
|
|||
##
|
||||
## **Performance Note:** This runs slightly faster than [Str.startsWith], so
|
||||
## if you want to check whether a string begins with something that's representable
|
||||
## in a single code point, you can use (for example) `Str.startsWithCodePt '鹏'`
|
||||
## instead of `Str.startsWithCodePt "鹏"`. ('鹏' evaluates to the [U32]
|
||||
## in a single code point, you can use (for example) `Str.startsWithScalar '鹏'`
|
||||
## instead of `Str.startsWithScalar "鹏"`. ('鹏' evaluates to the [U32]
|
||||
## value `40527`.) This will not work for graphemes which take up multiple code
|
||||
## points, however; `Str.startsWithCodePt '👩👩👦👦'` would be a compiler error
|
||||
## points, however; `Str.startsWithScalar '👩👩👦👦'` would be a compiler error
|
||||
## because 👩👩👦👦 takes up multiple code points and cannot be represented as a
|
||||
## single [U32]. You'd need to use `Str.startsWithCodePt "🕊"` instead.
|
||||
startsWithCodePt : Str, U32 -> Bool
|
||||
## single [U32]. You'd need to use `Str.startsWithScalar "🕊"` instead.
|
||||
startsWithScalar : Str, U32 -> Bool
|
||||
|
||||
## Return a [List] of the [unicode scalar values](https://unicode.org/glossary/#unicode_scalar_value)
|
||||
## in the given string.
|
||||
##
|
||||
## (Strings contain only scalar values, not [surrogate code points](https://unicode.org/glossary/#surrogate_code_point),
|
||||
## so this is equivalent to returning a list of the string's [code points](https://unicode.org/glossary/#code_point).)
|
||||
toScalars : Str -> List U32
|
||||
|
||||
## Return a [List] of the string's [U8] UTF-8 [code units](https://unicode.org/glossary/#code_unit).
|
||||
## (To split the string into a [List] of smaller [Str] values instead of [U8] values,
|
||||
|
|
|
@ -311,9 +311,10 @@ pub const STR_COUNT_SEGMENTS: &str = "roc_builtins.str.count_segments";
|
|||
pub const STR_CONCAT: &str = "roc_builtins.str.concat";
|
||||
pub const STR_JOIN_WITH: &str = "roc_builtins.str.joinWith";
|
||||
pub const STR_STR_SPLIT_IN_PLACE: &str = "roc_builtins.str.str_split_in_place";
|
||||
pub const STR_TO_SCALARS: &str = "roc_builtins.str.to_scalars";
|
||||
pub const STR_COUNT_GRAPEHEME_CLUSTERS: &str = "roc_builtins.str.count_grapheme_clusters";
|
||||
pub const STR_STARTS_WITH: &str = "roc_builtins.str.starts_with";
|
||||
pub const STR_STARTS_WITH_CODE_PT: &str = "roc_builtins.str.starts_with_code_point";
|
||||
pub const STR_STARTS_WITH_SCALAR: &str = "roc_builtins.str.starts_with_scalar";
|
||||
pub const STR_ENDS_WITH: &str = "roc_builtins.str.ends_with";
|
||||
pub const STR_NUMBER_OF_BYTES: &str = "roc_builtins.str.number_of_bytes";
|
||||
pub const STR_FROM_INT: IntrinsicName = int_intrinsic!("roc_builtins.str.from_int");
|
||||
|
@ -353,26 +354,16 @@ pub const LIST_MAP2: &str = "roc_builtins.list.map2";
|
|||
pub const LIST_MAP3: &str = "roc_builtins.list.map3";
|
||||
pub const LIST_MAP4: &str = "roc_builtins.list.map4";
|
||||
pub const LIST_MAP_WITH_INDEX: &str = "roc_builtins.list.map_with_index";
|
||||
pub const LIST_WALK: &str = "roc_builtins.list.walk";
|
||||
pub const LIST_WALK_UNTIL: &str = "roc_builtins.list.walkUntil";
|
||||
pub const LIST_WALK_BACKWARDS: &str = "roc_builtins.list.walk_backwards";
|
||||
pub const LIST_CONTAINS: &str = "roc_builtins.list.contains";
|
||||
pub const LIST_REPEAT: &str = "roc_builtins.list.repeat";
|
||||
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_DROP_AT: &str = "roc_builtins.list.drop_at";
|
||||
pub const LIST_SWAP: &str = "roc_builtins.list.swap";
|
||||
pub const LIST_SINGLE: &str = "roc_builtins.list.single";
|
||||
pub const LIST_WITH_CAPACITY: &str = "roc_builtins.list.with_capacity";
|
||||
pub const LIST_REVERSE: &str = "roc_builtins.list.reverse";
|
||||
pub const LIST_SORT_WITH: &str = "roc_builtins.list.sort_with";
|
||||
pub const LIST_CONCAT: &str = "roc_builtins.list.concat";
|
||||
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_ANY: &str = "roc_builtins.list.any";
|
||||
pub const LIST_ALL: &str = "roc_builtins.list.all";
|
||||
pub const LIST_FIND_UNSAFE: &str = "roc_builtins.list.find_unsafe";
|
||||
pub const LIST_IS_UNIQUE: &str = "roc_builtins.list.is_unique";
|
||||
|
||||
pub const DEC_FROM_STR: &str = "roc_builtins.dec.from_str";
|
||||
|
|
|
@ -873,6 +873,13 @@ pub fn types() -> MutMap<Symbol, (SolvedType, Region)> {
|
|||
Box::new(str_type()),
|
||||
);
|
||||
|
||||
// Str.toScalars : Str -> List U32
|
||||
add_top_level_function_type!(
|
||||
Symbol::STR_TO_SCALARS,
|
||||
vec![str_type()],
|
||||
Box::new(list_type(u32_type())),
|
||||
);
|
||||
|
||||
// isEmpty : Str -> Bool
|
||||
add_top_level_function_type!(
|
||||
Symbol::STR_IS_EMPTY,
|
||||
|
@ -887,9 +894,9 @@ pub fn types() -> MutMap<Symbol, (SolvedType, Region)> {
|
|||
Box::new(bool_type())
|
||||
);
|
||||
|
||||
// startsWithCodePt : Str, U32 -> Bool
|
||||
// startsWithScalar : Str, U32 -> Bool
|
||||
add_top_level_function_type!(
|
||||
Symbol::STR_STARTS_WITH_CODE_PT,
|
||||
Symbol::STR_STARTS_WITH_SCALAR,
|
||||
vec![str_type(), u32_type()],
|
||||
Box::new(bool_type())
|
||||
);
|
||||
|
|
|
@ -73,10 +73,11 @@ pub fn builtin_defs_map(symbol: Symbol, var_store: &mut VarStore) -> Option<Def>
|
|||
BOOL_NOT => bool_not,
|
||||
STR_CONCAT => str_concat,
|
||||
STR_JOIN_WITH => str_join_with,
|
||||
STR_TO_SCALARS => str_to_scalars,
|
||||
STR_SPLIT => str_split,
|
||||
STR_IS_EMPTY => str_is_empty,
|
||||
STR_STARTS_WITH => str_starts_with,
|
||||
STR_STARTS_WITH_CODE_PT => str_starts_with_code_point,
|
||||
STR_STARTS_WITH_SCALAR => str_starts_with_scalar,
|
||||
STR_ENDS_WITH => str_ends_with,
|
||||
STR_COUNT_GRAPHEMES => str_count_graphemes,
|
||||
STR_FROM_UTF8 => str_from_utf8,
|
||||
|
@ -115,14 +116,10 @@ pub fn builtin_defs_map(symbol: Symbol, var_store: &mut VarStore) -> Option<Def>
|
|||
LIST_MAP4 => list_map4,
|
||||
LIST_SUBLIST => list_sublist,
|
||||
LIST_SPLIT => list_split,
|
||||
LIST_INTERSPERSE => list_intersperse,
|
||||
LIST_DROP => list_drop,
|
||||
LIST_DROP_AT => list_drop_at,
|
||||
LIST_SWAP => list_swap,
|
||||
LIST_MAP_WITH_INDEX => list_map_with_index,
|
||||
LIST_WALK => list_walk,
|
||||
LIST_WALK_BACKWARDS => list_walk_backwards,
|
||||
LIST_WALK_UNTIL => list_walk_until,
|
||||
LIST_SORT_WITH => list_sort_with,
|
||||
LIST_IS_UNIQUE => list_is_unique,
|
||||
DICT_LEN => dict_len,
|
||||
|
@ -1673,6 +1670,26 @@ fn str_concat(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
|||
)
|
||||
}
|
||||
|
||||
/// Str.toScalars : Str -> List U32
|
||||
fn str_to_scalars(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||
let str_var = var_store.fresh();
|
||||
let list_u32_var = var_store.fresh();
|
||||
|
||||
let body = RunLowLevel {
|
||||
op: LowLevel::StrToScalars,
|
||||
args: vec![(str_var, Var(Symbol::ARG_1))],
|
||||
ret_var: list_u32_var,
|
||||
};
|
||||
|
||||
defn(
|
||||
symbol,
|
||||
vec![(str_var, Symbol::ARG_1)],
|
||||
var_store,
|
||||
body,
|
||||
list_u32_var,
|
||||
)
|
||||
}
|
||||
|
||||
/// Str.joinWith : List Str, Str -> Str
|
||||
fn str_join_with(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||
let list_str_var = var_store.fresh();
|
||||
|
@ -1721,9 +1738,9 @@ fn str_starts_with(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
|||
lowlevel_2(symbol, LowLevel::StrStartsWith, var_store)
|
||||
}
|
||||
|
||||
/// Str.startsWithCodePt : Str, U32 -> Bool
|
||||
fn str_starts_with_code_point(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||
lowlevel_2(symbol, LowLevel::StrStartsWithCodePt, var_store)
|
||||
/// Str.startsWithScalar : Str, U32 -> Bool
|
||||
fn str_starts_with_scalar(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||
lowlevel_2(symbol, LowLevel::StrStartsWithScalar, var_store)
|
||||
}
|
||||
|
||||
/// Str.endsWith : Str, Str -> Bool
|
||||
|
@ -2165,96 +2182,6 @@ fn list_sublist(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
|||
)
|
||||
}
|
||||
|
||||
/// List.intersperse : List elem, elem -> List elem
|
||||
fn list_intersperse(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||
let list_var = var_store.fresh();
|
||||
let sep_var = var_store.fresh();
|
||||
|
||||
let list_sym = Symbol::ARG_1;
|
||||
let sep_sym = Symbol::ARG_2;
|
||||
|
||||
let clos_var = var_store.fresh();
|
||||
let clos_acc_var = var_store.fresh();
|
||||
|
||||
let clos_sym = Symbol::LIST_INTERSPERSE_CLOS;
|
||||
let clos_acc_sym = Symbol::ARG_3;
|
||||
let clos_elem_sym = Symbol::ARG_4;
|
||||
|
||||
let int_var = var_store.fresh();
|
||||
let zero = int::<i128>(
|
||||
int_var,
|
||||
Variable::NATURAL,
|
||||
0,
|
||||
IntBound::Exact(IntWidth::Nat),
|
||||
);
|
||||
|
||||
// \acc, elem -> acc |> List.append sep |> List.append elem
|
||||
let clos = Closure(ClosureData {
|
||||
function_type: clos_var,
|
||||
closure_type: var_store.fresh(),
|
||||
return_type: clos_acc_var,
|
||||
name: clos_sym,
|
||||
recursive: Recursive::NotRecursive,
|
||||
captured_symbols: vec![(sep_sym, sep_var)],
|
||||
arguments: vec![
|
||||
(
|
||||
clos_acc_var,
|
||||
AnnotatedMark::new(var_store),
|
||||
no_region(Pattern::Identifier(clos_acc_sym)),
|
||||
),
|
||||
(
|
||||
sep_var,
|
||||
AnnotatedMark::new(var_store),
|
||||
no_region(Pattern::Identifier(clos_elem_sym)),
|
||||
),
|
||||
],
|
||||
loc_body: {
|
||||
let append_sep = RunLowLevel {
|
||||
op: LowLevel::ListAppend,
|
||||
args: vec![(clos_acc_var, Var(clos_acc_sym)), (sep_var, Var(sep_sym))],
|
||||
ret_var: clos_acc_var,
|
||||
};
|
||||
|
||||
Box::new(no_region(RunLowLevel {
|
||||
op: LowLevel::ListAppend,
|
||||
args: vec![(clos_acc_var, append_sep), (sep_var, Var(clos_elem_sym))],
|
||||
ret_var: clos_acc_var,
|
||||
}))
|
||||
},
|
||||
});
|
||||
|
||||
// List.walk [] l (\acc, elem -> acc |> List.append sep |> List.append elem)
|
||||
let acc = RunLowLevel {
|
||||
op: LowLevel::ListWalk,
|
||||
args: vec![
|
||||
(list_var, Var(list_sym)),
|
||||
(
|
||||
clos_acc_var,
|
||||
List {
|
||||
elem_var: sep_var,
|
||||
loc_elems: vec![],
|
||||
},
|
||||
),
|
||||
(clos_var, clos),
|
||||
],
|
||||
ret_var: clos_acc_var,
|
||||
};
|
||||
|
||||
let body = RunLowLevel {
|
||||
op: LowLevel::ListDropAt,
|
||||
args: vec![(clos_acc_var, acc), (int_var, zero)],
|
||||
ret_var: clos_acc_var,
|
||||
};
|
||||
|
||||
defn(
|
||||
symbol,
|
||||
vec![(list_var, list_sym), (sep_var, sep_sym)],
|
||||
var_store,
|
||||
body,
|
||||
clos_acc_var,
|
||||
)
|
||||
}
|
||||
|
||||
/// List.split : List elem, Nat -> { before: List elem, others: List elem }
|
||||
fn list_split(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||
let list_var = var_store.fresh();
|
||||
|
@ -2461,21 +2388,6 @@ fn list_prepend(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
|||
)
|
||||
}
|
||||
|
||||
/// List.walk : List elem, state, (state, elem -> state) -> state
|
||||
fn list_walk(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||
lowlevel_3(symbol, LowLevel::ListWalk, var_store)
|
||||
}
|
||||
|
||||
/// List.walkBackwards : List elem, state, (state, elem -> state) -> state
|
||||
fn list_walk_backwards(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||
lowlevel_3(symbol, LowLevel::ListWalkBackwards, var_store)
|
||||
}
|
||||
|
||||
/// List.walkUntil : List elem, state, (state, elem -> [Continue state, Stop state]) -> state
|
||||
fn list_walk_until(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||
lowlevel_3(symbol, LowLevel::ListWalkUntil, var_store)
|
||||
}
|
||||
|
||||
/// List.unreachable : [] -> a
|
||||
fn roc_unreachable(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||
lowlevel_1(symbol, LowLevel::Unreachable, var_store)
|
||||
|
|
|
@ -8,10 +8,10 @@ use crate::llvm::build_dict::{
|
|||
};
|
||||
use crate::llvm::build_hash::generic_hash;
|
||||
use crate::llvm::build_list::{
|
||||
self, allocate_list, empty_polymorphic_list, list_all, list_any, list_append, list_concat,
|
||||
list_drop_at, list_find_unsafe, list_get_unsafe, list_len, list_map, list_map2, list_map3,
|
||||
list_map4, list_map_with_index, list_prepend, list_replace_unsafe, list_sort_with,
|
||||
list_sublist, list_swap, list_symbol_to_c_abi, list_to_c_abi, list_with_capacity,
|
||||
self, allocate_list, empty_polymorphic_list, list_append, list_concat, list_drop_at,
|
||||
list_get_unsafe, list_len, list_map, list_map2, list_map3, list_map4, list_map_with_index,
|
||||
list_prepend, list_replace_unsafe, list_sort_with, list_sublist, list_swap,
|
||||
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, str_split,
|
||||
|
@ -4881,44 +4881,6 @@ fn run_higher_order_low_level<'a, 'ctx, 'env>(
|
|||
}};
|
||||
}
|
||||
|
||||
macro_rules! list_walk {
|
||||
($variant:expr, $xs:expr, $state:expr) => {{
|
||||
let (list, list_layout) = load_symbol_and_layout(scope, &$xs);
|
||||
let (default, default_layout) = load_symbol_and_layout(scope, &$state);
|
||||
|
||||
let (function, closure, closure_layout) = function_details!();
|
||||
|
||||
match list_layout {
|
||||
Layout::Builtin(Builtin::List(element_layout)) => {
|
||||
let argument_layouts = &[*default_layout, **element_layout];
|
||||
|
||||
let roc_function_call = roc_function_call(
|
||||
env,
|
||||
layout_ids,
|
||||
function,
|
||||
closure,
|
||||
closure_layout,
|
||||
function_owns_closure_data,
|
||||
argument_layouts,
|
||||
result_layout,
|
||||
);
|
||||
|
||||
crate::llvm::build_list::list_walk_generic(
|
||||
env,
|
||||
layout_ids,
|
||||
roc_function_call,
|
||||
&result_layout,
|
||||
list,
|
||||
element_layout,
|
||||
default,
|
||||
default_layout,
|
||||
$variant,
|
||||
)
|
||||
}
|
||||
_ => unreachable!("invalid list layout"),
|
||||
}
|
||||
}};
|
||||
}
|
||||
match op {
|
||||
ListMap { xs } => {
|
||||
// List.map : List before, (before -> after) -> List after
|
||||
|
@ -5119,15 +5081,6 @@ fn run_higher_order_low_level<'a, 'ctx, 'env>(
|
|||
_ => unreachable!("invalid list layout"),
|
||||
}
|
||||
}
|
||||
ListWalk { xs, state } => {
|
||||
list_walk!(crate::llvm::build_list::ListWalk::Walk, xs, state)
|
||||
}
|
||||
ListWalkUntil { xs, state } => {
|
||||
list_walk!(crate::llvm::build_list::ListWalk::WalkUntil, xs, state)
|
||||
}
|
||||
ListWalkBackwards { xs, state } => {
|
||||
list_walk!(crate::llvm::build_list::ListWalk::WalkBackwards, xs, state)
|
||||
}
|
||||
ListSortWith { xs } => {
|
||||
// List.sortWith : List a, (a, a -> Ordering) -> List a
|
||||
let (list, list_layout) = load_symbol_and_layout(scope, xs);
|
||||
|
@ -5167,78 +5120,6 @@ fn run_higher_order_low_level<'a, 'ctx, 'env>(
|
|||
_ => unreachable!("invalid list layout"),
|
||||
}
|
||||
}
|
||||
ListAny { xs } => {
|
||||
let (list, list_layout) = load_symbol_and_layout(scope, xs);
|
||||
let (function, closure, closure_layout) = function_details!();
|
||||
|
||||
match list_layout {
|
||||
Layout::Builtin(Builtin::List(element_layout)) => {
|
||||
let argument_layouts = &[**element_layout];
|
||||
|
||||
let roc_function_call = roc_function_call(
|
||||
env,
|
||||
layout_ids,
|
||||
function,
|
||||
closure,
|
||||
closure_layout,
|
||||
function_owns_closure_data,
|
||||
argument_layouts,
|
||||
Layout::Builtin(Builtin::Bool),
|
||||
);
|
||||
|
||||
list_any(env, roc_function_call, list, element_layout)
|
||||
}
|
||||
_ => unreachable!("invalid list layout"),
|
||||
}
|
||||
}
|
||||
ListAll { xs } => {
|
||||
let (list, list_layout) = load_symbol_and_layout(scope, xs);
|
||||
let (function, closure, closure_layout) = function_details!();
|
||||
|
||||
match list_layout {
|
||||
Layout::Builtin(Builtin::List(element_layout)) => {
|
||||
let argument_layouts = &[**element_layout];
|
||||
|
||||
let roc_function_call = roc_function_call(
|
||||
env,
|
||||
layout_ids,
|
||||
function,
|
||||
closure,
|
||||
closure_layout,
|
||||
function_owns_closure_data,
|
||||
argument_layouts,
|
||||
Layout::Builtin(Builtin::Bool),
|
||||
);
|
||||
|
||||
list_all(env, roc_function_call, list, element_layout)
|
||||
}
|
||||
_ => unreachable!("invalid list layout"),
|
||||
}
|
||||
}
|
||||
ListFindUnsafe { xs } => {
|
||||
let (list, list_layout) = load_symbol_and_layout(scope, xs);
|
||||
|
||||
let (function, closure, closure_layout) = function_details!();
|
||||
|
||||
match list_layout {
|
||||
Layout::Builtin(Builtin::List(element_layout)) => {
|
||||
let argument_layouts = &[**element_layout];
|
||||
let roc_function_call = roc_function_call(
|
||||
env,
|
||||
layout_ids,
|
||||
function,
|
||||
closure,
|
||||
closure_layout,
|
||||
function_owns_closure_data,
|
||||
argument_layouts,
|
||||
Layout::Builtin(Builtin::Bool),
|
||||
);
|
||||
|
||||
list_find_unsafe(env, layout_ids, roc_function_call, list, element_layout)
|
||||
}
|
||||
_ => unreachable!("invalid list layout"),
|
||||
}
|
||||
}
|
||||
DictWalk { xs, state } => {
|
||||
let (dict, dict_layout) = load_symbol_and_layout(scope, xs);
|
||||
let (default, default_layout) = load_symbol_and_layout(scope, state);
|
||||
|
@ -5310,6 +5191,14 @@ fn run_low_level<'a, 'ctx, 'env>(
|
|||
|
||||
call_str_bitcode_fn(env, &[list.into(), string], bitcode::STR_JOIN_WITH)
|
||||
}
|
||||
StrToScalars => {
|
||||
// Str.toScalars : Str -> List U32
|
||||
debug_assert_eq!(args.len(), 1);
|
||||
|
||||
let string = load_symbol(scope, &args[0]);
|
||||
|
||||
call_list_bitcode_fn(env, &[string], bitcode::STR_TO_SCALARS)
|
||||
}
|
||||
StrStartsWith => {
|
||||
// Str.startsWith : Str, Str -> Bool
|
||||
debug_assert_eq!(args.len(), 2);
|
||||
|
@ -5319,14 +5208,14 @@ fn run_low_level<'a, 'ctx, 'env>(
|
|||
|
||||
call_bitcode_fn(env, &[string, prefix], bitcode::STR_STARTS_WITH)
|
||||
}
|
||||
StrStartsWithCodePt => {
|
||||
// Str.startsWithCodePt : Str, U32 -> Bool
|
||||
StrStartsWithScalar => {
|
||||
// Str.startsWithScalar : Str, U32 -> Bool
|
||||
debug_assert_eq!(args.len(), 2);
|
||||
|
||||
let string = load_symbol(scope, &args[0]);
|
||||
let prefix = load_symbol(scope, &args[1]);
|
||||
|
||||
call_bitcode_fn(env, &[string, prefix], bitcode::STR_STARTS_WITH_CODE_PT)
|
||||
call_bitcode_fn(env, &[string, prefix], bitcode::STR_STARTS_WITH_SCALAR)
|
||||
}
|
||||
StrEndsWith => {
|
||||
// Str.startsWith : Str, Str -> Bool
|
||||
|
@ -6056,8 +5945,7 @@ fn run_low_level<'a, 'ctx, 'env>(
|
|||
set
|
||||
}
|
||||
|
||||
ListMap | ListMap2 | ListMap3 | ListMap4 | ListMapWithIndex | ListWalk | ListWalkUntil
|
||||
| ListWalkBackwards | ListSortWith | ListFindUnsafe | DictWalk => {
|
||||
ListMap | ListMap2 | ListMap3 | ListMap4 | ListMapWithIndex | ListSortWith | DictWalk => {
|
||||
unreachable!("these are higher order, and are handled elsewhere")
|
||||
}
|
||||
|
||||
|
|
|
@ -1,8 +1,5 @@
|
|||
#![allow(clippy::too_many_arguments)]
|
||||
use crate::llvm::bitcode::{
|
||||
build_dec_wrapper, build_has_tag_id, build_inc_n_wrapper, build_inc_wrapper, call_bitcode_fn,
|
||||
call_list_bitcode_fn, call_void_bitcode_fn,
|
||||
};
|
||||
use crate::llvm::bitcode::{build_dec_wrapper, call_list_bitcode_fn};
|
||||
use crate::llvm::build::{
|
||||
allocate_with_refcount_help, cast_basic_basic, Env, RocFunctionCall, Scope,
|
||||
};
|
||||
|
@ -122,29 +119,6 @@ pub fn list_with_capacity<'a, 'ctx, 'env>(
|
|||
)
|
||||
}
|
||||
|
||||
/// List.repeat : elem, Nat -> List elem
|
||||
pub fn list_repeat<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
layout_ids: &mut LayoutIds<'a>,
|
||||
element: BasicValueEnum<'ctx>,
|
||||
element_layout: &Layout<'a>,
|
||||
list_len: IntValue<'ctx>,
|
||||
) -> BasicValueEnum<'ctx> {
|
||||
let inc_element_fn = build_inc_n_wrapper(env, layout_ids, element_layout);
|
||||
|
||||
call_list_bitcode_fn(
|
||||
env,
|
||||
&[
|
||||
list_len.into(),
|
||||
env.alignment_intvalue(element_layout),
|
||||
pass_element_as_opaque(env, element, *element_layout),
|
||||
layout_width(env, element_layout),
|
||||
inc_element_fn.as_global_value().as_pointer_value().into(),
|
||||
],
|
||||
bitcode::LIST_REPEAT,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn list_get_unsafe<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
layout_ids: &mut LayoutIds<'a>,
|
||||
|
@ -370,133 +344,6 @@ pub fn list_len<'ctx>(
|
|||
.into_int_value()
|
||||
}
|
||||
|
||||
pub enum ListWalk {
|
||||
Walk,
|
||||
WalkBackwards,
|
||||
WalkUntil,
|
||||
WalkBackwardsUntil,
|
||||
}
|
||||
|
||||
pub fn list_walk_generic<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
layout_ids: &mut LayoutIds<'a>,
|
||||
roc_function_call: RocFunctionCall<'ctx>,
|
||||
function_call_return_layout: &Layout<'a>,
|
||||
list: BasicValueEnum<'ctx>,
|
||||
element_layout: &Layout<'a>,
|
||||
default: BasicValueEnum<'ctx>,
|
||||
default_layout: &Layout<'a>,
|
||||
variant: ListWalk,
|
||||
) -> BasicValueEnum<'ctx> {
|
||||
let builder = env.builder;
|
||||
|
||||
let zig_function = match variant {
|
||||
ListWalk::Walk => bitcode::LIST_WALK,
|
||||
ListWalk::WalkBackwards => bitcode::LIST_WALK_BACKWARDS,
|
||||
ListWalk::WalkUntil => bitcode::LIST_WALK_UNTIL,
|
||||
ListWalk::WalkBackwardsUntil => todo!(),
|
||||
};
|
||||
|
||||
let default_ptr = if default_layout.is_passed_by_reference(env.target_info) {
|
||||
debug_assert!(default.is_pointer_value());
|
||||
default.into_pointer_value()
|
||||
} else {
|
||||
let default_ptr = builder.build_alloca(default.get_type(), "default_ptr");
|
||||
env.builder.build_store(default_ptr, default);
|
||||
default_ptr
|
||||
};
|
||||
|
||||
let result_ptr = {
|
||||
let basic_type = basic_type_from_layout(env, default_layout);
|
||||
env.builder.build_alloca(basic_type, "result")
|
||||
};
|
||||
|
||||
match variant {
|
||||
ListWalk::Walk | ListWalk::WalkBackwards => {
|
||||
call_void_bitcode_fn(
|
||||
env,
|
||||
&[
|
||||
list_to_c_abi(env, list).into(),
|
||||
roc_function_call.caller.into(),
|
||||
pass_as_opaque(env, roc_function_call.data),
|
||||
roc_function_call.inc_n_data.into(),
|
||||
roc_function_call.data_is_owned.into(),
|
||||
pass_as_opaque(env, default_ptr),
|
||||
env.alignment_intvalue(element_layout),
|
||||
layout_width(env, element_layout),
|
||||
layout_width(env, default_layout),
|
||||
pass_as_opaque(env, result_ptr),
|
||||
],
|
||||
zig_function,
|
||||
);
|
||||
}
|
||||
ListWalk::WalkUntil | ListWalk::WalkBackwardsUntil => {
|
||||
let function = env
|
||||
.builder
|
||||
.get_insert_block()
|
||||
.unwrap()
|
||||
.get_parent()
|
||||
.unwrap();
|
||||
|
||||
let has_tag_id = match function_call_return_layout {
|
||||
Layout::Union(union_layout) => build_has_tag_id(env, function, *union_layout),
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
let dec_element_fn = build_dec_wrapper(env, layout_ids, element_layout);
|
||||
call_void_bitcode_fn(
|
||||
env,
|
||||
&[
|
||||
list_to_c_abi(env, list).into(),
|
||||
roc_function_call.caller.into(),
|
||||
pass_as_opaque(env, roc_function_call.data),
|
||||
roc_function_call.inc_n_data.into(),
|
||||
roc_function_call.data_is_owned.into(),
|
||||
pass_as_opaque(env, default_ptr),
|
||||
env.alignment_intvalue(element_layout),
|
||||
layout_width(env, element_layout),
|
||||
layout_width(env, function_call_return_layout),
|
||||
layout_width(env, default_layout),
|
||||
has_tag_id_helper(env, has_tag_id).into(),
|
||||
dec_element_fn.as_global_value().as_pointer_value().into(),
|
||||
pass_as_opaque(env, result_ptr),
|
||||
],
|
||||
zig_function,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if default_layout.is_passed_by_reference(env.target_info) {
|
||||
result_ptr.into()
|
||||
} else {
|
||||
env.builder.build_load(result_ptr, "load_result")
|
||||
}
|
||||
}
|
||||
|
||||
fn has_tag_id_helper<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
has_tag_id: FunctionValue<'ctx>,
|
||||
) -> PointerValue<'ctx> {
|
||||
let u8_t = env.context.i8_type();
|
||||
let u16_t = env.context.i16_type();
|
||||
|
||||
let u8_ptr_t = u8_t.ptr_type(AddressSpace::Generic);
|
||||
|
||||
let struct_t = env
|
||||
.context
|
||||
.struct_type(&[u8_t.into(), env.ptr_int().into()], false);
|
||||
|
||||
let has_tag_id_type = struct_t
|
||||
.fn_type(&[u16_t.into(), u8_ptr_t.into()], false)
|
||||
.ptr_type(AddressSpace::Generic);
|
||||
|
||||
env.builder.build_pointer_cast(
|
||||
has_tag_id.as_global_value().as_pointer_value(),
|
||||
has_tag_id_type,
|
||||
"has_tag_id_cast",
|
||||
)
|
||||
}
|
||||
|
||||
/// List.sortWith : List a, (a, a -> Ordering) -> List a
|
||||
pub fn list_sort_with<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
|
@ -704,144 +551,6 @@ pub fn list_concat<'a, 'ctx, 'env>(
|
|||
)
|
||||
}
|
||||
|
||||
/// List.any : List elem, \(elem -> Bool) -> Bool
|
||||
pub fn list_any<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
roc_function_call: RocFunctionCall<'ctx>,
|
||||
list: BasicValueEnum<'ctx>,
|
||||
element_layout: &Layout<'a>,
|
||||
) -> BasicValueEnum<'ctx> {
|
||||
call_bitcode_fn(
|
||||
env,
|
||||
&[
|
||||
list_to_c_abi(env, list).into(),
|
||||
roc_function_call.caller.into(),
|
||||
pass_as_opaque(env, roc_function_call.data),
|
||||
roc_function_call.inc_n_data.into(),
|
||||
roc_function_call.data_is_owned.into(),
|
||||
layout_width(env, element_layout),
|
||||
],
|
||||
bitcode::LIST_ANY,
|
||||
)
|
||||
}
|
||||
|
||||
/// List.all : List elem, \(elem -> Bool) -> Bool
|
||||
pub fn list_all<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
roc_function_call: RocFunctionCall<'ctx>,
|
||||
list: BasicValueEnum<'ctx>,
|
||||
element_layout: &Layout<'a>,
|
||||
) -> BasicValueEnum<'ctx> {
|
||||
call_bitcode_fn(
|
||||
env,
|
||||
&[
|
||||
list_to_c_abi(env, list).into(),
|
||||
roc_function_call.caller.into(),
|
||||
pass_as_opaque(env, roc_function_call.data),
|
||||
roc_function_call.inc_n_data.into(),
|
||||
roc_function_call.data_is_owned.into(),
|
||||
layout_width(env, element_layout),
|
||||
],
|
||||
bitcode::LIST_ALL,
|
||||
)
|
||||
}
|
||||
|
||||
/// List.findUnsafe : List elem, (elem -> Bool) -> { value: elem, found: bool }
|
||||
pub fn list_find_unsafe<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
layout_ids: &mut LayoutIds<'a>,
|
||||
roc_function_call: RocFunctionCall<'ctx>,
|
||||
list: BasicValueEnum<'ctx>,
|
||||
element_layout: &Layout<'a>,
|
||||
) -> BasicValueEnum<'ctx> {
|
||||
let inc_element_fn = build_inc_wrapper(env, layout_ids, element_layout);
|
||||
let dec_element_fn = build_dec_wrapper(env, layout_ids, element_layout);
|
||||
|
||||
// { value: *const u8, found: bool }
|
||||
let result = call_bitcode_fn(
|
||||
env,
|
||||
&[
|
||||
list_to_c_abi(env, list).into(),
|
||||
roc_function_call.caller.into(),
|
||||
pass_as_opaque(env, roc_function_call.data),
|
||||
roc_function_call.inc_n_data.into(),
|
||||
roc_function_call.data_is_owned.into(),
|
||||
layout_width(env, element_layout),
|
||||
inc_element_fn.as_global_value().as_pointer_value().into(),
|
||||
dec_element_fn.as_global_value().as_pointer_value().into(),
|
||||
],
|
||||
bitcode::LIST_FIND_UNSAFE,
|
||||
)
|
||||
.into_struct_value();
|
||||
|
||||
// We promised the caller we'd give them back a struct containing the element
|
||||
// loaded on the stack, so we do that now. The element can't be loaded directly
|
||||
// in the Zig definition called above, because we don't know the size of the
|
||||
// element until user compile time, which is later than the compile time of bitcode defs.
|
||||
|
||||
let value_u8_ptr_int = env
|
||||
.builder
|
||||
.build_extract_value(result, 0, "get_value_ptr_int")
|
||||
.unwrap()
|
||||
.into_int_value();
|
||||
|
||||
let found_u8 = env
|
||||
.builder
|
||||
.build_extract_value(result, 1, "get_found")
|
||||
.unwrap()
|
||||
.into_int_value();
|
||||
|
||||
let found = env
|
||||
.builder
|
||||
.build_int_cast(found_u8, env.context.bool_type(), "found_as_bool");
|
||||
|
||||
let start_block = env.builder.get_insert_block().unwrap();
|
||||
let parent = start_block.get_parent().unwrap();
|
||||
|
||||
let if_not_null = env.context.append_basic_block(parent, "if_not_null");
|
||||
let done_block = env.context.append_basic_block(parent, "done");
|
||||
|
||||
let value_bt = basic_type_from_layout(env, element_layout);
|
||||
let default = value_bt.const_zero();
|
||||
|
||||
env.builder
|
||||
.build_conditional_branch(found, if_not_null, done_block);
|
||||
|
||||
env.builder.position_at_end(if_not_null);
|
||||
|
||||
let value_ptr = env.builder.build_int_to_ptr(
|
||||
value_u8_ptr_int,
|
||||
value_bt.ptr_type(AddressSpace::Generic),
|
||||
"get_value_ptr",
|
||||
);
|
||||
|
||||
let loaded = env.builder.build_load(value_ptr, "load_value");
|
||||
env.builder.build_unconditional_branch(done_block);
|
||||
|
||||
env.builder.position_at_end(done_block);
|
||||
let result_phi = env.builder.build_phi(value_bt, "result");
|
||||
|
||||
result_phi.add_incoming(&[(&default, start_block), (&loaded, if_not_null)]);
|
||||
|
||||
let value = result_phi.as_basic_value();
|
||||
|
||||
let result = env
|
||||
.context
|
||||
.struct_type(&[value_bt, env.context.bool_type().into()], false)
|
||||
.const_zero();
|
||||
|
||||
let result = env
|
||||
.builder
|
||||
.build_insert_value(result, value, 0, "insert_value")
|
||||
.unwrap();
|
||||
|
||||
env.builder
|
||||
.build_insert_value(result, found, 1, "insert_found")
|
||||
.unwrap()
|
||||
.into_struct_value()
|
||||
.into()
|
||||
}
|
||||
|
||||
pub fn decrementing_elem_loop<'ctx, LoopFn>(
|
||||
builder: &Builder<'ctx>,
|
||||
ctx: &'ctx Context,
|
||||
|
|
|
@ -1304,35 +1304,49 @@ impl<'a> WasmBackend<'a> {
|
|||
storage: &StoredValue,
|
||||
fields: &'a [Symbol],
|
||||
) {
|
||||
if matches!(layout, Layout::Struct { .. }) {
|
||||
match storage {
|
||||
StoredValue::StackMemory { location, size, .. } => {
|
||||
if *size > 0 {
|
||||
let (local_id, struct_offset) =
|
||||
location.local_and_offset(self.storage.stack_frame_pointer);
|
||||
let mut field_offset = struct_offset;
|
||||
for field in fields.iter() {
|
||||
field_offset += self.storage.copy_value_to_memory(
|
||||
&mut self.code_builder,
|
||||
local_id,
|
||||
field_offset,
|
||||
*field,
|
||||
);
|
||||
match layout {
|
||||
Layout::Struct { .. } => {
|
||||
match storage {
|
||||
StoredValue::StackMemory { location, size, .. } => {
|
||||
if *size > 0 {
|
||||
let (local_id, struct_offset) =
|
||||
location.local_and_offset(self.storage.stack_frame_pointer);
|
||||
let mut field_offset = struct_offset;
|
||||
for field in fields.iter() {
|
||||
field_offset += self.storage.copy_value_to_memory(
|
||||
&mut self.code_builder,
|
||||
local_id,
|
||||
field_offset,
|
||||
*field,
|
||||
);
|
||||
}
|
||||
} else {
|
||||
// Zero-size struct. No code to emit.
|
||||
// These values are purely conceptual, they only exist internally in the compiler
|
||||
}
|
||||
} else {
|
||||
// Zero-size struct. No code to emit.
|
||||
// These values are purely conceptual, they only exist internally in the compiler
|
||||
}
|
||||
_ => {
|
||||
internal_error!("Cannot create struct {:?} with storage {:?}", sym, storage)
|
||||
}
|
||||
};
|
||||
}
|
||||
Layout::LambdaSet(lambdaset) => {
|
||||
self.expr_struct(sym, &lambdaset.runtime_representation(), storage, fields)
|
||||
}
|
||||
_ => {
|
||||
if !fields.is_empty() {
|
||||
// Struct expression but not Struct layout => single element. Copy it.
|
||||
let field_storage = self.storage.get(&fields[0]).to_owned();
|
||||
self.storage.clone_value(
|
||||
&mut self.code_builder,
|
||||
storage,
|
||||
&field_storage,
|
||||
fields[0],
|
||||
);
|
||||
} else {
|
||||
// Empty record. Nothing to do.
|
||||
}
|
||||
_ => internal_error!("Cannot create struct {:?} with storage {:?}", sym, storage),
|
||||
};
|
||||
} else if !fields.is_empty() {
|
||||
// Struct expression but not Struct layout => single element. Copy it.
|
||||
let field_storage = self.storage.get(&fields[0]).to_owned();
|
||||
self.storage
|
||||
.clone_value(&mut self.code_builder, storage, &field_storage, fields[0]);
|
||||
} else {
|
||||
// Empty record. Nothing to do.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -217,6 +217,7 @@ impl<'a> LowLevelCall<'a> {
|
|||
match self.lowlevel {
|
||||
// Str
|
||||
StrConcat => self.load_args_and_call_zig(backend, bitcode::STR_CONCAT),
|
||||
StrToScalars => self.load_args_and_call_zig(backend, bitcode::STR_TO_SCALARS),
|
||||
StrJoinWith => self.load_args_and_call_zig(backend, bitcode::STR_JOIN_WITH),
|
||||
StrIsEmpty => match backend.storage.get(&self.arguments[0]) {
|
||||
StoredValue::StackMemory { location, .. } => {
|
||||
|
@ -230,8 +231,8 @@ impl<'a> LowLevelCall<'a> {
|
|||
_ => internal_error!("invalid storage for Str"),
|
||||
},
|
||||
StrStartsWith => self.load_args_and_call_zig(backend, bitcode::STR_STARTS_WITH),
|
||||
StrStartsWithCodePt => {
|
||||
self.load_args_and_call_zig(backend, bitcode::STR_STARTS_WITH_CODE_PT)
|
||||
StrStartsWithScalar => {
|
||||
self.load_args_and_call_zig(backend, bitcode::STR_STARTS_WITH_SCALAR)
|
||||
}
|
||||
StrEndsWith => self.load_args_and_call_zig(backend, bitcode::STR_ENDS_WITH),
|
||||
StrSplit => {
|
||||
|
@ -288,8 +289,8 @@ impl<'a> LowLevelCall<'a> {
|
|||
|
||||
ListIsUnique => self.load_args_and_call_zig(backend, bitcode::LIST_IS_UNIQUE),
|
||||
|
||||
ListMap | ListMap2 | ListMap3 | ListMap4 | ListMapWithIndex | ListWalk
|
||||
| ListWalkUntil | ListWalkBackwards | ListSortWith | ListFindUnsafe | DictWalk => {
|
||||
ListMap | ListMap2 | ListMap3 | ListMap4 | ListMapWithIndex | ListSortWith
|
||||
| DictWalk => {
|
||||
internal_error!("HigherOrder lowlevels should not be handled here")
|
||||
}
|
||||
|
||||
|
@ -556,7 +557,50 @@ impl<'a> LowLevelCall<'a> {
|
|||
|
||||
backend.call_host_fn_after_loading_args(bitcode::LIST_SUBLIST, 8, false);
|
||||
}
|
||||
ListDropAt => todo!("{:?}", self.lowlevel),
|
||||
ListDropAt => {
|
||||
// List.dropAt : List elem, Nat -> List elem
|
||||
let list: Symbol = self.arguments[0];
|
||||
let drop_index: Symbol = self.arguments[1];
|
||||
|
||||
let elem_layout = unwrap_list_elem_layout(self.ret_layout);
|
||||
let (elem_width, elem_align) = elem_layout.stack_size_and_alignment(TARGET_INFO);
|
||||
|
||||
// The refcount function receives a pointer to an element in the list
|
||||
// This is the same as a Struct containing the element
|
||||
let in_memory_layout = Layout::Struct {
|
||||
field_order_hash: FieldOrderHash::from_ordered_fields(&[]),
|
||||
field_layouts: backend.env.arena.alloc([*elem_layout]),
|
||||
};
|
||||
let dec_fn = backend.get_refcount_fn_index(in_memory_layout, HelperOp::Dec);
|
||||
let dec_fn_ptr = backend.get_fn_ptr(dec_fn);
|
||||
|
||||
// Zig arguments Wasm types
|
||||
// (return pointer) i32
|
||||
// list: RocList, i64, i32
|
||||
// element_width: usize, i32
|
||||
// alignment: u32, i32
|
||||
// drop_index: usize, i32
|
||||
// dec: Dec, i32
|
||||
|
||||
// Load the return pointer and the 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.i32_const(elem_width as i32);
|
||||
backend.code_builder.i32_const(elem_align as i32);
|
||||
backend
|
||||
.storage
|
||||
.load_symbols(&mut backend.code_builder, &[drop_index]);
|
||||
backend.code_builder.i32_const(dec_fn_ptr);
|
||||
|
||||
backend.call_host_fn_after_loading_args(bitcode::LIST_DROP_AT, 6, false);
|
||||
}
|
||||
ListSwap => {
|
||||
// List.swap : List elem, Nat, Nat -> List elem
|
||||
let list: Symbol = self.arguments[0];
|
||||
|
@ -2028,15 +2072,7 @@ pub fn call_higher_order_lowlevel<'a>(
|
|||
*owns_captured_environment,
|
||||
),
|
||||
|
||||
ListMapWithIndex { .. }
|
||||
| ListWalk { .. }
|
||||
| ListWalkUntil { .. }
|
||||
| ListWalkBackwards { .. }
|
||||
| ListSortWith { .. }
|
||||
| ListAny { .. }
|
||||
| ListAll { .. }
|
||||
| ListFindUnsafe { .. }
|
||||
| DictWalk { .. } => todo!("{:?}", op),
|
||||
ListMapWithIndex { .. } | ListSortWith { .. } | DictWalk { .. } => todo!("{:?}", op),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -3,11 +3,12 @@ use roc_std::{RocDec, RocList, RocOrder, RocStr};
|
|||
pub trait Wasm32Sized: Sized {
|
||||
const SIZE_OF_WASM: usize;
|
||||
const ALIGN_OF_WASM: usize;
|
||||
const ACTUAL_WIDTH: usize = if (Self::SIZE_OF_WASM % Self::ALIGN_OF_WASM) == 0 {
|
||||
Self::SIZE_OF_WASM
|
||||
} else {
|
||||
Self::SIZE_OF_WASM + (Self::ALIGN_OF_WASM - (Self::SIZE_OF_WASM % Self::ALIGN_OF_WASM))
|
||||
};
|
||||
const ACTUAL_WIDTH: usize =
|
||||
if (Self::ALIGN_OF_WASM == 0) || (Self::SIZE_OF_WASM % Self::ALIGN_OF_WASM) == 0 {
|
||||
Self::SIZE_OF_WASM
|
||||
} else {
|
||||
Self::SIZE_OF_WASM + (Self::ALIGN_OF_WASM - (Self::SIZE_OF_WASM % Self::ALIGN_OF_WASM))
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! wasm32_sized_primitive {
|
||||
|
|
|
@ -9,7 +9,7 @@ pub enum LowLevel {
|
|||
StrJoinWith,
|
||||
StrIsEmpty,
|
||||
StrStartsWith,
|
||||
StrStartsWithCodePt,
|
||||
StrStartsWithScalar,
|
||||
StrEndsWith,
|
||||
StrSplit,
|
||||
StrCountGraphemes,
|
||||
|
@ -23,6 +23,7 @@ pub enum LowLevel {
|
|||
StrTrimLeft,
|
||||
StrTrimRight,
|
||||
StrToNum,
|
||||
StrToScalars,
|
||||
ListLen,
|
||||
ListWithCapacity,
|
||||
ListGetUnsafe,
|
||||
|
@ -35,14 +36,10 @@ pub enum LowLevel {
|
|||
ListMap3,
|
||||
ListMap4,
|
||||
ListMapWithIndex,
|
||||
ListWalk,
|
||||
ListWalkUntil,
|
||||
ListWalkBackwards,
|
||||
ListSortWith,
|
||||
ListSublist,
|
||||
ListDropAt,
|
||||
ListSwap,
|
||||
ListFindUnsafe,
|
||||
ListIsUnique,
|
||||
DictSize,
|
||||
DictEmpty,
|
||||
|
@ -124,17 +121,7 @@ pub enum LowLevel {
|
|||
|
||||
macro_rules! higher_order {
|
||||
() => {
|
||||
ListMap
|
||||
| ListMap2
|
||||
| ListMap3
|
||||
| ListMap4
|
||||
| ListMapWithIndex
|
||||
| ListWalk
|
||||
| ListWalkUntil
|
||||
| ListWalkBackwards
|
||||
| ListSortWith
|
||||
| ListFindUnsafe
|
||||
| DictWalk
|
||||
ListMap | ListMap2 | ListMap3 | ListMap4 | ListMapWithIndex | ListSortWith | DictWalk
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -156,11 +143,7 @@ impl LowLevel {
|
|||
ListMap3 => 3,
|
||||
ListMap4 => 4,
|
||||
ListMapWithIndex => 1,
|
||||
ListWalk => 2,
|
||||
ListWalkUntil => 2,
|
||||
ListWalkBackwards => 2,
|
||||
ListSortWith => 1,
|
||||
ListFindUnsafe => 1,
|
||||
DictWalk => 2,
|
||||
_ => unreachable!(),
|
||||
}
|
||||
|
@ -185,10 +168,11 @@ impl LowLevelWrapperType {
|
|||
|
||||
match symbol {
|
||||
Symbol::STR_CONCAT => CanBeReplacedBy(StrConcat),
|
||||
Symbol::STR_TO_SCALARS => CanBeReplacedBy(StrToScalars),
|
||||
Symbol::STR_JOIN_WITH => CanBeReplacedBy(StrJoinWith),
|
||||
Symbol::STR_IS_EMPTY => CanBeReplacedBy(StrIsEmpty),
|
||||
Symbol::STR_STARTS_WITH => CanBeReplacedBy(StrStartsWith),
|
||||
Symbol::STR_STARTS_WITH_CODE_PT => CanBeReplacedBy(StrStartsWithCodePt),
|
||||
Symbol::STR_STARTS_WITH_SCALAR => CanBeReplacedBy(StrStartsWithScalar),
|
||||
Symbol::STR_ENDS_WITH => CanBeReplacedBy(StrEndsWith),
|
||||
Symbol::STR_SPLIT => CanBeReplacedBy(StrSplit),
|
||||
Symbol::STR_COUNT_GRAPHEMES => CanBeReplacedBy(StrCountGraphemes),
|
||||
|
@ -224,9 +208,6 @@ impl LowLevelWrapperType {
|
|||
Symbol::LIST_MAP3 => WrapperIsRequired,
|
||||
Symbol::LIST_MAP4 => WrapperIsRequired,
|
||||
Symbol::LIST_MAP_WITH_INDEX => WrapperIsRequired,
|
||||
Symbol::LIST_WALK => WrapperIsRequired,
|
||||
Symbol::LIST_WALK_UNTIL => WrapperIsRequired,
|
||||
Symbol::LIST_WALK_BACKWARDS => WrapperIsRequired,
|
||||
Symbol::LIST_SORT_WITH => WrapperIsRequired,
|
||||
Symbol::LIST_SUBLIST => WrapperIsRequired,
|
||||
Symbol::LIST_DROP_AT => CanBeReplacedBy(ListDropAt),
|
||||
|
|
|
@ -1168,7 +1168,7 @@ define_builtins! {
|
|||
10 STR_UT8_PROBLEM: "Utf8Problem" // the Utf8Problem type alias
|
||||
11 STR_UT8_BYTE_PROBLEM: "Utf8ByteProblem" // the Utf8ByteProblem type alias
|
||||
12 STR_TO_UTF8: "toUtf8"
|
||||
13 STR_STARTS_WITH_CODE_PT: "startsWithCodePt"
|
||||
13 STR_STARTS_WITH_SCALAR: "startsWithScalar"
|
||||
14 STR_ALIAS_ANALYSIS_STATIC: "#aliasAnalysisStatic" // string with the static lifetime
|
||||
15 STR_FROM_UTF8_RANGE: "fromUtf8Range"
|
||||
16 STR_REPEAT: "repeat"
|
||||
|
@ -1189,6 +1189,7 @@ define_builtins! {
|
|||
31 STR_TO_I16: "toI16"
|
||||
32 STR_TO_U8: "toU8"
|
||||
33 STR_TO_I8: "toI8"
|
||||
34 STR_TO_SCALARS: "toScalars"
|
||||
}
|
||||
5 LIST: "List" => {
|
||||
0 LIST_LIST: "List" imported // the List.List type alias
|
||||
|
|
|
@ -552,7 +552,7 @@ impl<'a> BorrowInfState<'a> {
|
|||
};
|
||||
|
||||
match op {
|
||||
ListMap { xs } | ListAny { xs } | ListAll { xs } | ListFindUnsafe { xs } => {
|
||||
ListMap { xs } => {
|
||||
// own the list if the function wants to own the element
|
||||
if !function_ps[0].borrow {
|
||||
self.own_var(*xs);
|
||||
|
@ -606,10 +606,7 @@ impl<'a> BorrowInfState<'a> {
|
|||
// always own the input list
|
||||
self.own_var(*xs);
|
||||
}
|
||||
ListWalk { xs, state }
|
||||
| ListWalkUntil { xs, state }
|
||||
| ListWalkBackwards { xs, state }
|
||||
| DictWalk { xs, state } => {
|
||||
DictWalk { xs, state } => {
|
||||
// own the default value if the function wants to own it
|
||||
if !function_ps[0].borrow {
|
||||
self.own_var(*state);
|
||||
|
@ -891,7 +888,9 @@ pub fn lowlevel_borrow_signature(arena: &Bump, op: LowLevel) -> &[bool] {
|
|||
// - other refcounted arguments are Borrowed
|
||||
match op {
|
||||
Unreachable => arena.alloc_slice_copy(&[irrelevant]),
|
||||
ListLen | StrIsEmpty | StrCountGraphemes => arena.alloc_slice_copy(&[borrowed]),
|
||||
ListLen | StrIsEmpty | StrToScalars | StrCountGraphemes => {
|
||||
arena.alloc_slice_copy(&[borrowed])
|
||||
}
|
||||
ListWithCapacity => arena.alloc_slice_copy(&[irrelevant]),
|
||||
ListReplaceUnsafe => arena.alloc_slice_copy(&[owned, irrelevant, irrelevant]),
|
||||
ListGetUnsafe => arena.alloc_slice_copy(&[borrowed, irrelevant]),
|
||||
|
@ -908,11 +907,7 @@ pub fn lowlevel_borrow_signature(arena: &Bump, op: LowLevel) -> &[bool] {
|
|||
ListMap2 => arena.alloc_slice_copy(&[owned, owned, function, closure_data]),
|
||||
ListMap3 => arena.alloc_slice_copy(&[owned, owned, owned, function, closure_data]),
|
||||
ListMap4 => arena.alloc_slice_copy(&[owned, owned, owned, owned, function, closure_data]),
|
||||
ListWalk | ListWalkUntil | ListWalkBackwards => {
|
||||
arena.alloc_slice_copy(&[owned, owned, function, closure_data])
|
||||
}
|
||||
ListSortWith => arena.alloc_slice_copy(&[owned, function, closure_data]),
|
||||
ListFindUnsafe => arena.alloc_slice_copy(&[owned, function, closure_data]),
|
||||
|
||||
// TODO when we have lists with capacity (if ever)
|
||||
// List.append should own its first argument
|
||||
|
@ -938,7 +933,7 @@ pub fn lowlevel_borrow_signature(arena: &Bump, op: LowLevel) -> &[bool] {
|
|||
NumBytesToU16 => arena.alloc_slice_copy(&[borrowed, irrelevant]),
|
||||
NumBytesToU32 => arena.alloc_slice_copy(&[borrowed, irrelevant]),
|
||||
StrStartsWith | StrEndsWith => arena.alloc_slice_copy(&[owned, borrowed]),
|
||||
StrStartsWithCodePt => arena.alloc_slice_copy(&[borrowed, irrelevant]),
|
||||
StrStartsWithScalar => arena.alloc_slice_copy(&[borrowed, irrelevant]),
|
||||
StrFromUtf8 => arena.alloc_slice_copy(&[owned]),
|
||||
StrFromUtf8Range => arena.alloc_slice_copy(&[borrowed, irrelevant]),
|
||||
StrToUtf8 => arena.alloc_slice_copy(&[owned]),
|
||||
|
|
|
@ -693,7 +693,7 @@ impl<'a> Context<'a> {
|
|||
let after_arguments = &arguments[op.function_index()..];
|
||||
|
||||
match *op {
|
||||
ListMap { xs } | ListAny { xs } | ListAll { xs } | ListFindUnsafe { xs } => {
|
||||
ListMap { xs } => {
|
||||
let ownerships = [(xs, function_ps[0])];
|
||||
|
||||
let b = self.add_dec_after_lowlevel(after_arguments, &borrows, b, b_live_vars);
|
||||
|
@ -820,10 +820,7 @@ impl<'a> Context<'a> {
|
|||
|
||||
handle_ownerships_pre!(Stmt::Let(z, v, l, b), ownerships)
|
||||
}
|
||||
ListWalk { xs, state: _ }
|
||||
| ListWalkUntil { xs, state: _ }
|
||||
| ListWalkBackwards { xs, state: _ }
|
||||
| DictWalk { xs, state: _ } => {
|
||||
DictWalk { xs, state: _ } => {
|
||||
let ownerships = [
|
||||
// borrow data structure based on second argument of the folded function
|
||||
(xs, function_ps[1]),
|
||||
|
|
|
@ -5048,9 +5048,6 @@ pub fn with_hole<'a>(
|
|||
let xs = arg_symbols[0];
|
||||
match_on_closure_argument!(ListSortWith, [xs])
|
||||
}
|
||||
ListWalk => walk!(ListWalk),
|
||||
ListWalkUntil => walk!(ListWalkUntil),
|
||||
ListWalkBackwards => walk!(ListWalkBackwards),
|
||||
DictWalk => walk!(DictWalk),
|
||||
ListMap2 => {
|
||||
debug_assert_eq!(arg_symbols.len(), 3);
|
||||
|
@ -5079,11 +5076,6 @@ pub fn with_hole<'a>(
|
|||
|
||||
match_on_closure_argument!(ListMap4, [xs, ys, zs, ws])
|
||||
}
|
||||
ListFindUnsafe => {
|
||||
debug_assert_eq!(arg_symbols.len(), 2);
|
||||
let xs = arg_symbols[0];
|
||||
match_on_closure_argument!(ListFindUnsafe, [xs])
|
||||
}
|
||||
BoxExpr => {
|
||||
debug_assert_eq!(arg_symbols.len(), 1);
|
||||
let x = arg_symbols[0];
|
||||
|
|
|
@ -23,30 +23,9 @@ pub enum HigherOrder {
|
|||
ListMapWithIndex {
|
||||
xs: Symbol,
|
||||
},
|
||||
ListWalk {
|
||||
xs: Symbol,
|
||||
state: Symbol,
|
||||
},
|
||||
ListWalkUntil {
|
||||
xs: Symbol,
|
||||
state: Symbol,
|
||||
},
|
||||
ListWalkBackwards {
|
||||
xs: Symbol,
|
||||
state: Symbol,
|
||||
},
|
||||
ListSortWith {
|
||||
xs: Symbol,
|
||||
},
|
||||
ListAny {
|
||||
xs: Symbol,
|
||||
},
|
||||
ListAll {
|
||||
xs: Symbol,
|
||||
},
|
||||
ListFindUnsafe {
|
||||
xs: Symbol,
|
||||
},
|
||||
DictWalk {
|
||||
xs: Symbol,
|
||||
state: Symbol,
|
||||
|
@ -61,14 +40,8 @@ impl HigherOrder {
|
|||
HigherOrder::ListMap3 { .. } => 3,
|
||||
HigherOrder::ListMap4 { .. } => 4,
|
||||
HigherOrder::ListMapWithIndex { .. } => 2,
|
||||
HigherOrder::ListWalk { .. } => 2,
|
||||
HigherOrder::ListWalkUntil { .. } => 2,
|
||||
HigherOrder::ListWalkBackwards { .. } => 2,
|
||||
HigherOrder::ListSortWith { .. } => 2,
|
||||
HigherOrder::ListFindUnsafe { .. } => 1,
|
||||
HigherOrder::DictWalk { .. } => 2,
|
||||
HigherOrder::ListAny { .. } => 1,
|
||||
HigherOrder::ListAll { .. } => 1,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -78,18 +51,11 @@ impl HigherOrder {
|
|||
use HigherOrder::*;
|
||||
|
||||
match self {
|
||||
ListMap { .. }
|
||||
| ListMapWithIndex { .. }
|
||||
| ListSortWith { .. }
|
||||
| ListAny { .. }
|
||||
| ListAll { .. }
|
||||
| ListFindUnsafe { .. } => 2,
|
||||
ListMap { .. } | ListMapWithIndex { .. } | ListSortWith { .. } => 2,
|
||||
ListMap2 { .. } => 3,
|
||||
ListMap3 { .. } => 4,
|
||||
ListMap4 { .. } => 5,
|
||||
ListWalk { .. } | ListWalkUntil { .. } | ListWalkBackwards { .. } | DictWalk { .. } => {
|
||||
3
|
||||
}
|
||||
DictWalk { .. } => 3,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -105,7 +71,7 @@ enum FirstOrder {
|
|||
StrJoinWith,
|
||||
StrIsEmpty,
|
||||
StrStartsWith,
|
||||
StrStartsWithCodePt,
|
||||
StrStartsWithScalar,
|
||||
StrEndsWith,
|
||||
StrSplit,
|
||||
StrCountGraphemes,
|
||||
|
|
|
@ -32,7 +32,7 @@ fn empty_list_literal() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn list_literal_empty_record() {
|
||||
assert_evals_to!("[{}]", RocList::from_slice(&[()]), RocList<()>);
|
||||
}
|
||||
|
@ -168,7 +168,7 @@ fn list_append() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn list_take_first() {
|
||||
assert_evals_to!(
|
||||
"List.takeFirst [1, 2, 3] 2",
|
||||
|
@ -193,7 +193,7 @@ fn list_take_first() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn list_take_last() {
|
||||
assert_evals_to!(
|
||||
"List.takeLast [1, 2, 3] 2",
|
||||
|
@ -258,7 +258,7 @@ fn list_sublist() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn list_split() {
|
||||
assert_evals_to!(
|
||||
r#"
|
||||
|
@ -328,7 +328,7 @@ fn list_drop() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn list_drop_at() {
|
||||
assert_evals_to!(
|
||||
"List.dropAt [1, 2, 3] 0",
|
||||
|
@ -376,7 +376,7 @@ fn list_intersperse() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn list_drop_at_shared() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
|
@ -691,7 +691,7 @@ fn list_prepend_big_list() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn list_walk_backwards_empty_all_inline() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
|
@ -719,7 +719,7 @@ fn list_walk_backwards_empty_all_inline() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn list_walk_backwards_with_str() {
|
||||
assert_evals_to!(
|
||||
r#"List.walkBackwards ["x", "y", "z"] "<" Str.concat"#,
|
||||
|
@ -735,7 +735,7 @@ fn list_walk_backwards_with_str() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn list_walk_backwards_with_record() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
|
@ -763,7 +763,7 @@ fn list_walk_backwards_with_record() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn list_walk_with_str() {
|
||||
assert_evals_to!(
|
||||
r#"List.walk ["x", "y", "z"] "<" Str.concat"#,
|
||||
|
@ -779,13 +779,13 @@ fn list_walk_with_str() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn list_walk_subtraction() {
|
||||
assert_evals_to!(r#"List.walk [1, 2] 1 Num.sub"#, (1 - 1) - 2, i64);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn list_walk_until_sum() {
|
||||
assert_evals_to!(
|
||||
r#"List.walkUntil [1, 2] 0 \a,b -> Continue (a + b)"#,
|
||||
|
@ -823,7 +823,7 @@ fn list_walk_implements_position() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn list_walk_until_even_prefix_sum() {
|
||||
assert_evals_to!(
|
||||
r#"
|
||||
|
@ -1079,7 +1079,7 @@ fn list_map_all_inline() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn list_map_closure() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
|
@ -1197,7 +1197,7 @@ fn list_map2_different_lengths() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn list_join_empty_list() {
|
||||
assert_evals_to!(
|
||||
"List.join []",
|
||||
|
@ -1207,7 +1207,7 @@ fn list_join_empty_list() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn list_join_one_list() {
|
||||
assert_evals_to!(
|
||||
"List.join [[1, 2, 3]]",
|
||||
|
@ -1217,7 +1217,7 @@ fn list_join_one_list() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn list_join_two_non_empty_lists() {
|
||||
assert_evals_to!(
|
||||
"List.join [[1, 2, 3] , [4 ,5, 6]]",
|
||||
|
@ -1227,7 +1227,7 @@ fn list_join_two_non_empty_lists() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn list_join_two_non_empty_lists_of_float() {
|
||||
assert_evals_to!(
|
||||
"List.join [[1.2, 1.1], [2.1, 2.2]]",
|
||||
|
@ -1237,7 +1237,7 @@ fn list_join_two_non_empty_lists_of_float() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn list_join_to_big_list() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
|
@ -1263,7 +1263,7 @@ fn list_join_to_big_list() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn list_join_defined_empty_list() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
|
@ -1281,7 +1281,7 @@ fn list_join_defined_empty_list() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn list_join_all_empty_lists() {
|
||||
assert_evals_to!(
|
||||
"List.join [[], [], []]",
|
||||
|
@ -1291,7 +1291,7 @@ fn list_join_all_empty_lists() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn list_join_one_empty_list() {
|
||||
assert_evals_to!(
|
||||
"List.join [[1.2, 1.1], []]",
|
||||
|
@ -2000,7 +2000,7 @@ fn gen_wrap_len() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn gen_wrap_first() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
|
@ -2381,7 +2381,7 @@ fn list_wrap_in_tag() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn list_contains_int() {
|
||||
assert_evals_to!(indoc!("List.contains [1,2,3] 1"), true, bool);
|
||||
|
||||
|
@ -2391,7 +2391,7 @@ fn list_contains_int() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn list_contains_str() {
|
||||
assert_evals_to!(indoc!(r#"List.contains ["foo", "bar"] "bar""#), true, bool);
|
||||
|
||||
|
@ -2426,7 +2426,7 @@ fn list_manual_range() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn list_min() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
|
@ -2453,7 +2453,7 @@ fn list_min() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn list_max() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
|
@ -2480,7 +2480,7 @@ fn list_max() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn list_sum() {
|
||||
assert_evals_to!("List.sum []", 0, i64);
|
||||
assert_evals_to!("List.sum [1, 2, 3]", 6, i64);
|
||||
|
@ -2488,7 +2488,7 @@ fn list_sum() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn list_product() {
|
||||
assert_evals_to!("List.product []", 1, i64);
|
||||
assert_evals_to!("List.product [1, 2, 3]", 6, i64);
|
||||
|
@ -2663,7 +2663,7 @@ fn list_sort_desc() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn list_any() {
|
||||
assert_evals_to!("List.any [] (\\e -> e > 3)", false, bool);
|
||||
assert_evals_to!("List.any [1, 2, 3] (\\e -> e > 3)", false, bool);
|
||||
|
@ -2687,7 +2687,7 @@ fn list_any_empty_with_unknown_element_type() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn list_all() {
|
||||
assert_evals_to!("List.all [] (\\e -> e > 3)", true, bool);
|
||||
assert_evals_to!("List.all [1, 2, 3] (\\e -> e > 3)", false, bool);
|
||||
|
@ -2811,7 +2811,7 @@ fn list_join_map_empty() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn list_find() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
|
@ -2827,7 +2827,7 @@ fn list_find() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn list_find_not_found() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
|
@ -2843,7 +2843,7 @@ fn list_find_not_found() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn list_find_empty_typed_list() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
|
@ -2859,7 +2859,7 @@ fn list_find_empty_typed_list() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
#[ignore = "Fails because monomorphization can't be done if we don't have a concrete element type!"]
|
||||
fn list_find_empty_layout() {
|
||||
assert_evals_to!(
|
||||
|
|
|
@ -496,14 +496,14 @@ fn str_starts_with() {
|
|||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
fn str_starts_with_code_point() {
|
||||
fn str_starts_with_scalar() {
|
||||
assert_evals_to!(
|
||||
&format!(r#"Str.startsWithCodePt "foobar" {}"#, 'f' as u32),
|
||||
&format!(r#"Str.startsWithScalar "foobar" {}"#, 'f' as u32),
|
||||
true,
|
||||
bool
|
||||
);
|
||||
assert_evals_to!(
|
||||
&format!(r#"Str.startsWithCodePt "zoobar" {}"#, 'f' as u32),
|
||||
&format!(r#"Str.startsWithScalar "zoobar" {}"#, 'f' as u32),
|
||||
false,
|
||||
bool
|
||||
);
|
||||
|
@ -1603,3 +1603,100 @@ fn issue_2811() {
|
|||
RocStr
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
fn to_scalar_1_byte() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
r#"
|
||||
Str.toScalars "R"
|
||||
"#
|
||||
),
|
||||
RocList::from_slice(&[82u32]),
|
||||
RocList<u32>
|
||||
);
|
||||
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
r#"
|
||||
Str.toScalars "Roc!"
|
||||
"#
|
||||
),
|
||||
RocList::from_slice(&[82u32, 111, 99, 33]),
|
||||
RocList<u32>
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
fn to_scalar_2_byte() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
r#"
|
||||
Str.toScalars "é"
|
||||
"#
|
||||
),
|
||||
RocList::from_slice(&[233u32]),
|
||||
RocList<u32>
|
||||
);
|
||||
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
r#"
|
||||
Str.toScalars "Cäfés"
|
||||
"#
|
||||
),
|
||||
RocList::from_slice(&[67u32, 228, 102, 233, 115]),
|
||||
RocList<u32>
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
fn to_scalar_3_byte() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
r#"
|
||||
Str.toScalars "鹏"
|
||||
"#
|
||||
),
|
||||
RocList::from_slice(&[40527u32]),
|
||||
RocList<u32>
|
||||
);
|
||||
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
r#"
|
||||
Str.toScalars "鹏很有趣"
|
||||
"#
|
||||
),
|
||||
RocList::from_slice(&[40527u32, 24456, 26377, 36259]),
|
||||
RocList<u32>
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
fn to_scalar_4_byte() {
|
||||
// from https://design215.com/toolbox/utf8-4byte-characters.php
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
r#"
|
||||
Str.toScalars "𒀀"
|
||||
"#
|
||||
),
|
||||
RocList::from_slice(&[73728u32]),
|
||||
RocList<u32>
|
||||
);
|
||||
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
r#"
|
||||
Str.toScalars "𒀀𒀁"
|
||||
"#
|
||||
),
|
||||
RocList::from_slice(&[73728u32, 73729u32]),
|
||||
RocList<u32>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -417,14 +417,14 @@ fn str_starts_with() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
fn str_starts_with_code_point() {
|
||||
fn str_starts_with_scalar() {
|
||||
assert_evals_to!(
|
||||
&format!(r#"Str.startsWithCodePt "foobar" {}"#, 'f' as u32),
|
||||
&format!(r#"Str.startsWithScalar "foobar" {}"#, 'f' as u32),
|
||||
true,
|
||||
bool
|
||||
);
|
||||
assert_evals_to!(
|
||||
&format!(r#"Str.startsWithCodePt "zoobar" {}"#, 'f' as u32),
|
||||
&format!(r#"Str.startsWithScalar "zoobar" {}"#, 'f' as u32),
|
||||
false,
|
||||
bool
|
||||
);
|
||||
|
|
|
@ -1,17 +0,0 @@
|
|||
procedure Test.2 (Test.6, #Attr.12):
|
||||
let Test.1 : U8 = StructAtIndex 0 #Attr.12;
|
||||
let Test.11 : {U8} = Struct {Test.1};
|
||||
ret Test.11;
|
||||
|
||||
procedure Test.4 (Test.5, #Attr.12):
|
||||
let Test.1 : U8 = StructAtIndex 0 #Attr.12;
|
||||
ret Test.1;
|
||||
|
||||
procedure Test.0 ():
|
||||
let Test.1 : U8 = 1i64;
|
||||
let Test.8 : {} = Struct {};
|
||||
let Test.10 : {} = Struct {};
|
||||
let Test.14 : {U8} = Struct {Test.1};
|
||||
let Test.9 : {U8} = CallByName Test.2 Test.10 Test.14;
|
||||
let Test.7 : U8 = CallByName Test.4 Test.8 Test.9;
|
||||
ret Test.7;
|
|
@ -1,6 +1,6 @@
|
|||
procedure List.6 (#Attr.2):
|
||||
let List.261 : U64 = lowlevel ListLen #Attr.2;
|
||||
ret List.261;
|
||||
let List.286 : U64 = lowlevel ListLen #Attr.2;
|
||||
ret List.286;
|
||||
|
||||
procedure Test.1 (Test.5):
|
||||
let Test.2 : I64 = 41i64;
|
||||
|
|
|
@ -1,22 +1,22 @@
|
|||
procedure List.2 (List.74, List.75):
|
||||
let List.267 : U64 = CallByName List.6 List.74;
|
||||
let List.263 : Int1 = CallByName Num.22 List.75 List.267;
|
||||
if List.263 then
|
||||
let List.265 : {} = CallByName List.60 List.74 List.75;
|
||||
let List.264 : [C {}, C {}] = Ok List.265;
|
||||
ret List.264;
|
||||
procedure List.2 (List.76, List.77):
|
||||
let List.292 : U64 = CallByName List.6 List.76;
|
||||
let List.288 : Int1 = CallByName Num.22 List.77 List.292;
|
||||
if List.288 then
|
||||
let List.290 : {} = CallByName List.60 List.76 List.77;
|
||||
let List.289 : [C {}, C {}] = Ok List.290;
|
||||
ret List.289;
|
||||
else
|
||||
let List.262 : {} = Struct {};
|
||||
let List.261 : [C {}, C {}] = Err List.262;
|
||||
ret List.261;
|
||||
let List.287 : {} = Struct {};
|
||||
let List.286 : [C {}, C {}] = Err List.287;
|
||||
ret List.286;
|
||||
|
||||
procedure List.6 (#Attr.2):
|
||||
let List.270 : U64 = lowlevel ListLen #Attr.2;
|
||||
ret List.270;
|
||||
let List.295 : U64 = lowlevel ListLen #Attr.2;
|
||||
ret List.295;
|
||||
|
||||
procedure List.60 (#Attr.2, #Attr.3):
|
||||
let List.269 : {} = lowlevel ListGetUnsafe #Attr.2 #Attr.3;
|
||||
ret List.269;
|
||||
let List.294 : {} = lowlevel ListGetUnsafe #Attr.2 #Attr.3;
|
||||
ret List.294;
|
||||
|
||||
procedure Num.22 (#Attr.2, #Attr.3):
|
||||
let Num.273 : Int1 = lowlevel NumLt #Attr.2 #Attr.3;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
procedure List.4 (#Attr.2, #Attr.3):
|
||||
let List.261 : List U8 = lowlevel ListAppend #Attr.2 #Attr.3;
|
||||
ret List.261;
|
||||
let List.286 : List U8 = lowlevel ListAppend #Attr.2 #Attr.3;
|
||||
ret List.286;
|
||||
|
||||
procedure Test.20 (Test.22):
|
||||
let Test.34 : {U8} = Struct {Test.22};
|
||||
|
|
|
@ -1,104 +0,0 @@
|
|||
procedure Encode.22 (Encode.93):
|
||||
ret Encode.93;
|
||||
|
||||
procedure Encode.22 (Encode.93):
|
||||
ret Encode.93;
|
||||
|
||||
procedure Encode.23 (Encode.94, Encode.102, Encode.96):
|
||||
let Encode.107 : List U8 = CallByName Test.3 Encode.94 Encode.96;
|
||||
ret Encode.107;
|
||||
|
||||
procedure Encode.23 (Encode.94, Encode.102, Encode.96):
|
||||
let Encode.114 : List U8 = CallByName Json.65 Encode.94 Encode.96 Encode.102;
|
||||
ret Encode.114;
|
||||
|
||||
procedure Encode.25 (Encode.100, Encode.101):
|
||||
let Encode.104 : List U8 = Array [];
|
||||
let Encode.105 : {} = CallByName Test.2 Encode.100;
|
||||
let Encode.103 : List U8 = CallByName Encode.23 Encode.104 Encode.105 Encode.101;
|
||||
ret Encode.103;
|
||||
|
||||
procedure Json.1 ():
|
||||
let Json.102 : {} = Struct {};
|
||||
ret Json.102;
|
||||
|
||||
procedure Json.17 (Json.64):
|
||||
let Json.104 : {Str} = Struct {Json.64};
|
||||
let Json.103 : {Str} = CallByName Encode.22 Json.104;
|
||||
ret Json.103;
|
||||
|
||||
procedure Json.65 (Json.66, Json.105, #Attr.12):
|
||||
let Json.64 : Str = StructAtIndex 0 #Attr.12;
|
||||
inc Json.64;
|
||||
dec #Attr.12;
|
||||
let Json.114 : I32 = 34i64;
|
||||
let Json.113 : U8 = CallByName Num.122 Json.114;
|
||||
let Json.111 : List U8 = CallByName List.4 Json.66 Json.113;
|
||||
let Json.112 : List U8 = CallByName Str.12 Json.64;
|
||||
let Json.108 : List U8 = CallByName List.8 Json.111 Json.112;
|
||||
let Json.110 : I32 = 34i64;
|
||||
let Json.109 : U8 = CallByName Num.122 Json.110;
|
||||
let Json.107 : List U8 = CallByName List.4 Json.108 Json.109;
|
||||
ret Json.107;
|
||||
|
||||
procedure List.4 (#Attr.2, #Attr.3):
|
||||
let List.141 : List U8 = lowlevel ListAppend #Attr.2 #Attr.3;
|
||||
ret List.141;
|
||||
|
||||
procedure List.8 (#Attr.2, #Attr.3):
|
||||
let List.142 : List U8 = lowlevel ListConcat #Attr.2 #Attr.3;
|
||||
ret List.142;
|
||||
|
||||
procedure Num.122 (#Attr.2):
|
||||
let Num.272 : U8 = lowlevel NumIntCast #Attr.2;
|
||||
ret Num.272;
|
||||
|
||||
procedure Str.12 (#Attr.2):
|
||||
let Str.73 : List U8 = lowlevel StrToUtf8 #Attr.2;
|
||||
ret Str.73;
|
||||
|
||||
procedure Str.9 (#Attr.2):
|
||||
let #Attr.3 : {U64, Str, Int1, U8} = lowlevel StrFromUtf8 #Attr.2;
|
||||
let Str.69 : Int1 = StructAtIndex 2 #Attr.3;
|
||||
if Str.69 then
|
||||
let Str.71 : Str = StructAtIndex 1 #Attr.3;
|
||||
inc Str.71;
|
||||
dec #Attr.3;
|
||||
let Str.70 : [C {U64, U8}, C Str] = Ok Str.71;
|
||||
ret Str.70;
|
||||
else
|
||||
let Str.67 : U8 = StructAtIndex 3 #Attr.3;
|
||||
let Str.68 : U64 = StructAtIndex 0 #Attr.3;
|
||||
dec #Attr.3;
|
||||
let Str.66 : {U64, U8} = Struct {Str.68, Str.67};
|
||||
let Str.65 : [C {U64, U8}, C Str] = Err Str.66;
|
||||
ret Str.65;
|
||||
|
||||
procedure Test.2 (Test.8):
|
||||
let Test.18 : {} = Struct {};
|
||||
let Test.17 : {} = CallByName Encode.22 Test.18;
|
||||
ret Test.17;
|
||||
|
||||
procedure Test.3 (Test.4, Test.5):
|
||||
let Test.21 : Str = "Hello, World!\n";
|
||||
let Test.20 : {Str} = CallByName Json.17 Test.21;
|
||||
let Test.19 : List U8 = CallByName Encode.23 Test.4 Test.20 Test.5;
|
||||
ret Test.19;
|
||||
|
||||
procedure Test.0 ():
|
||||
let Test.15 : {} = Struct {};
|
||||
let Test.16 : {} = CallByName Json.1;
|
||||
let Test.14 : List U8 = CallByName Encode.25 Test.15 Test.16;
|
||||
let Test.6 : [C {U64, U8}, C Str] = CallByName Str.9 Test.14;
|
||||
let Test.11 : U8 = 1i64;
|
||||
let Test.12 : U8 = GetTagId Test.6;
|
||||
let Test.13 : Int1 = lowlevel Eq Test.11 Test.12;
|
||||
if Test.13 then
|
||||
let Test.7 : Str = UnionAtIndex (Id 1) (Index 0) Test.6;
|
||||
inc Test.7;
|
||||
dec Test.6;
|
||||
ret Test.7;
|
||||
else
|
||||
dec Test.6;
|
||||
let Test.10 : Str = "<bad>";
|
||||
ret Test.10;
|
|
@ -1,30 +0,0 @@
|
|||
procedure Test.4 (Test.30):
|
||||
joinpoint Test.14 Test.5:
|
||||
let Test.24 : Int1 = 1i64;
|
||||
let Test.25 : Int1 = GetTagId Test.5;
|
||||
let Test.26 : Int1 = lowlevel Eq Test.24 Test.25;
|
||||
if Test.26 then
|
||||
let Test.15 : Int1 = false;
|
||||
ret Test.15;
|
||||
else
|
||||
let Test.20 : [C I64, C ] = UnionAtIndex (Id 0) (Index 0) Test.5;
|
||||
let Test.21 : U8 = 1i64;
|
||||
let Test.22 : U8 = GetTagId Test.20;
|
||||
let Test.23 : Int1 = lowlevel Eq Test.21 Test.22;
|
||||
if Test.23 then
|
||||
let Test.16 : Int1 = true;
|
||||
ret Test.16;
|
||||
else
|
||||
let Test.8 : [<rnu><null>, C [C I64, C ] *self] = UnionAtIndex (Id 0) (Index 1) Test.5;
|
||||
jump Test.14 Test.8;
|
||||
in
|
||||
jump Test.14 Test.30;
|
||||
|
||||
procedure Test.0 ():
|
||||
let Test.29 : I64 = 3i64;
|
||||
let Test.27 : [C I64, C ] = Just Test.29;
|
||||
let Test.28 : [<rnu><null>, C [C I64, C ] *self] = Nil ;
|
||||
let Test.13 : [<rnu><null>, C [C I64, C ] *self] = Cons Test.27 Test.28;
|
||||
let Test.12 : Int1 = CallByName Test.4 Test.13;
|
||||
dec Test.13;
|
||||
ret Test.12;
|
|
@ -1,6 +1,6 @@
|
|||
procedure List.6 (#Attr.2):
|
||||
let List.261 : U64 = lowlevel ListLen #Attr.2;
|
||||
ret List.261;
|
||||
let List.286 : U64 = lowlevel ListLen #Attr.2;
|
||||
ret List.286;
|
||||
|
||||
procedure Num.19 (#Attr.2, #Attr.3):
|
||||
let Num.275 : U64 = lowlevel NumAdd #Attr.2 #Attr.3;
|
||||
|
|
|
@ -1,37 +1,37 @@
|
|||
procedure List.2 (List.74, List.75):
|
||||
let List.276 : U64 = CallByName List.6 List.74;
|
||||
let List.272 : Int1 = CallByName Num.22 List.75 List.276;
|
||||
if List.272 then
|
||||
let List.274 : I64 = CallByName List.60 List.74 List.75;
|
||||
let List.273 : [C {}, C I64] = Ok List.274;
|
||||
ret List.273;
|
||||
procedure List.2 (List.76, List.77):
|
||||
let List.301 : U64 = CallByName List.6 List.76;
|
||||
let List.297 : Int1 = CallByName Num.22 List.77 List.301;
|
||||
if List.297 then
|
||||
let List.299 : I64 = CallByName List.60 List.76 List.77;
|
||||
let List.298 : [C {}, C I64] = Ok List.299;
|
||||
ret List.298;
|
||||
else
|
||||
let List.271 : {} = Struct {};
|
||||
let List.270 : [C {}, C I64] = Err List.271;
|
||||
ret List.270;
|
||||
let List.296 : {} = Struct {};
|
||||
let List.295 : [C {}, C I64] = Err List.296;
|
||||
ret List.295;
|
||||
|
||||
procedure List.6 (#Attr.2):
|
||||
let List.277 : U64 = lowlevel ListLen #Attr.2;
|
||||
ret List.277;
|
||||
let List.302 : U64 = lowlevel ListLen #Attr.2;
|
||||
ret List.302;
|
||||
|
||||
procedure List.60 (#Attr.2, #Attr.3):
|
||||
let List.275 : I64 = lowlevel ListGetUnsafe #Attr.2 #Attr.3;
|
||||
ret List.275;
|
||||
let List.300 : I64 = lowlevel ListGetUnsafe #Attr.2 #Attr.3;
|
||||
ret List.300;
|
||||
|
||||
procedure List.9 (List.185):
|
||||
let List.268 : U64 = 0i64;
|
||||
let List.261 : [C {}, C I64] = CallByName List.2 List.185 List.268;
|
||||
let List.265 : U8 = 1i64;
|
||||
let List.266 : U8 = GetTagId List.261;
|
||||
let List.267 : Int1 = lowlevel Eq List.265 List.266;
|
||||
if List.267 then
|
||||
let List.186 : I64 = UnionAtIndex (Id 1) (Index 0) List.261;
|
||||
let List.262 : [C Int1, C I64] = Ok List.186;
|
||||
ret List.262;
|
||||
procedure List.9 (List.203):
|
||||
let List.293 : U64 = 0i64;
|
||||
let List.286 : [C {}, C I64] = CallByName List.2 List.203 List.293;
|
||||
let List.290 : U8 = 1i64;
|
||||
let List.291 : U8 = GetTagId List.286;
|
||||
let List.292 : Int1 = lowlevel Eq List.290 List.291;
|
||||
if List.292 then
|
||||
let List.204 : I64 = UnionAtIndex (Id 1) (Index 0) List.286;
|
||||
let List.287 : [C Int1, C I64] = Ok List.204;
|
||||
ret List.287;
|
||||
else
|
||||
let List.264 : Int1 = true;
|
||||
let List.263 : [C Int1, C I64] = Err List.264;
|
||||
ret List.263;
|
||||
let List.289 : Int1 = true;
|
||||
let List.288 : [C Int1, C I64] = Err List.289;
|
||||
ret List.288;
|
||||
|
||||
procedure Num.22 (#Attr.2, #Attr.3):
|
||||
let Num.273 : Int1 = lowlevel NumLt #Attr.2 #Attr.3;
|
||||
|
@ -39,17 +39,17 @@ procedure Num.22 (#Attr.2, #Attr.3):
|
|||
|
||||
procedure Str.27 (#Attr.2):
|
||||
let #Attr.3 : {I64, U8} = lowlevel StrToNum #Attr.2;
|
||||
let Str.70 : U8 = StructAtIndex 1 #Attr.3;
|
||||
let Str.71 : U8 = 0i64;
|
||||
let Str.67 : Int1 = lowlevel NumGt Str.70 Str.71;
|
||||
if Str.67 then
|
||||
let Str.69 : Int1 = false;
|
||||
let Str.68 : [C Int1, C I64] = Err Str.69;
|
||||
ret Str.68;
|
||||
let Str.72 : U8 = StructAtIndex 1 #Attr.3;
|
||||
let Str.73 : U8 = 0i64;
|
||||
let Str.69 : Int1 = lowlevel NumGt Str.72 Str.73;
|
||||
if Str.69 then
|
||||
let Str.71 : Int1 = false;
|
||||
let Str.70 : [C Int1, C I64] = Err Str.71;
|
||||
ret Str.70;
|
||||
else
|
||||
let Str.66 : I64 = StructAtIndex 0 #Attr.3;
|
||||
let Str.65 : [C Int1, C I64] = Ok Str.66;
|
||||
ret Str.65;
|
||||
let Str.68 : I64 = StructAtIndex 0 #Attr.3;
|
||||
let Str.67 : [C Int1, C I64] = Ok Str.68;
|
||||
ret Str.67;
|
||||
|
||||
procedure Test.0 ():
|
||||
let Test.4 : Int1 = true;
|
||||
|
|
|
@ -1,25 +0,0 @@
|
|||
procedure Num.19 (#Attr.2, #Attr.3):
|
||||
let Num.274 : I64 = lowlevel NumAdd #Attr.2 #Attr.3;
|
||||
ret Num.274;
|
||||
|
||||
procedure Test.4 (Test.6):
|
||||
let Test.16 : Int1 = 1i64;
|
||||
let Test.17 : Int1 = GetTagId Test.6;
|
||||
let Test.18 : Int1 = lowlevel Eq Test.16 Test.17;
|
||||
if Test.18 then
|
||||
let Test.12 : I64 = 0i64;
|
||||
ret Test.12;
|
||||
else
|
||||
let Test.7 : [<rnu><null>, C I64 *self] = UnionAtIndex (Id 0) (Index 1) Test.6;
|
||||
let Test.14 : I64 = 1i64;
|
||||
let Test.15 : I64 = CallByName Test.4 Test.7;
|
||||
let Test.13 : I64 = CallByName Num.19 Test.14 Test.15;
|
||||
ret Test.13;
|
||||
|
||||
procedure Test.0 ():
|
||||
let Test.3 : [<rnu><null>, C I64 *self] = Nil ;
|
||||
let Test.9 : I64 = CallByName Test.4 Test.3;
|
||||
let Test.10 : I64 = CallByName Test.4 Test.3;
|
||||
dec Test.3;
|
||||
let Test.8 : I64 = CallByName Num.19 Test.9 Test.10;
|
||||
ret Test.8;
|
|
@ -1,6 +1,6 @@
|
|||
procedure List.4 (#Attr.2, #Attr.3):
|
||||
let List.261 : List I64 = lowlevel ListAppend #Attr.2 #Attr.3;
|
||||
ret List.261;
|
||||
let List.286 : List I64 = lowlevel ListAppend #Attr.2 #Attr.3;
|
||||
ret List.286;
|
||||
|
||||
procedure Test.0 ():
|
||||
let Test.2 : List I64 = Array [1i64];
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
procedure List.4 (#Attr.2, #Attr.3):
|
||||
let List.261 : List I64 = lowlevel ListAppend #Attr.2 #Attr.3;
|
||||
ret List.261;
|
||||
let List.286 : List I64 = lowlevel ListAppend #Attr.2 #Attr.3;
|
||||
ret List.286;
|
||||
|
||||
procedure Test.1 (Test.2):
|
||||
let Test.6 : I64 = 42i64;
|
||||
|
|
|
@ -1,27 +1,27 @@
|
|||
procedure List.3 (List.83, List.84, List.85):
|
||||
let List.264 : {List I64, I64} = CallByName List.57 List.83 List.84 List.85;
|
||||
let List.263 : List I64 = StructAtIndex 0 List.264;
|
||||
inc List.263;
|
||||
dec List.264;
|
||||
ret List.263;
|
||||
procedure List.3 (List.85, List.86, List.87):
|
||||
let List.289 : {List I64, I64} = CallByName List.57 List.85 List.86 List.87;
|
||||
let List.288 : List I64 = StructAtIndex 0 List.289;
|
||||
inc List.288;
|
||||
dec List.289;
|
||||
ret List.288;
|
||||
|
||||
procedure List.57 (List.80, List.81, List.82):
|
||||
let List.270 : U64 = CallByName List.6 List.80;
|
||||
let List.267 : Int1 = CallByName Num.22 List.81 List.270;
|
||||
if List.267 then
|
||||
let List.268 : {List I64, I64} = CallByName List.61 List.80 List.81 List.82;
|
||||
ret List.268;
|
||||
procedure List.57 (List.82, List.83, List.84):
|
||||
let List.295 : U64 = CallByName List.6 List.82;
|
||||
let List.292 : Int1 = CallByName Num.22 List.83 List.295;
|
||||
if List.292 then
|
||||
let List.293 : {List I64, I64} = CallByName List.61 List.82 List.83 List.84;
|
||||
ret List.293;
|
||||
else
|
||||
let List.266 : {List I64, I64} = Struct {List.80, List.82};
|
||||
ret List.266;
|
||||
let List.291 : {List I64, I64} = Struct {List.82, List.84};
|
||||
ret List.291;
|
||||
|
||||
procedure List.6 (#Attr.2):
|
||||
let List.262 : U64 = lowlevel ListLen #Attr.2;
|
||||
ret List.262;
|
||||
let List.287 : U64 = lowlevel ListLen #Attr.2;
|
||||
ret List.287;
|
||||
|
||||
procedure List.61 (#Attr.2, #Attr.3, #Attr.4):
|
||||
let List.269 : {List I64, I64} = lowlevel ListReplaceUnsafe #Attr.2 #Attr.3 #Attr.4;
|
||||
ret List.269;
|
||||
let List.294 : {List I64, I64} = lowlevel ListReplaceUnsafe #Attr.2 #Attr.3 #Attr.4;
|
||||
ret List.294;
|
||||
|
||||
procedure Num.19 (#Attr.2, #Attr.3):
|
||||
let Num.273 : U64 = lowlevel NumAdd #Attr.2 #Attr.3;
|
||||
|
|
|
@ -1,22 +1,22 @@
|
|||
procedure List.2 (List.74, List.75):
|
||||
let List.267 : U64 = CallByName List.6 List.74;
|
||||
let List.263 : Int1 = CallByName Num.22 List.75 List.267;
|
||||
if List.263 then
|
||||
let List.265 : I64 = CallByName List.60 List.74 List.75;
|
||||
let List.264 : [C {}, C I64] = Ok List.265;
|
||||
ret List.264;
|
||||
procedure List.2 (List.76, List.77):
|
||||
let List.292 : U64 = CallByName List.6 List.76;
|
||||
let List.288 : Int1 = CallByName Num.22 List.77 List.292;
|
||||
if List.288 then
|
||||
let List.290 : I64 = CallByName List.60 List.76 List.77;
|
||||
let List.289 : [C {}, C I64] = Ok List.290;
|
||||
ret List.289;
|
||||
else
|
||||
let List.262 : {} = Struct {};
|
||||
let List.261 : [C {}, C I64] = Err List.262;
|
||||
ret List.261;
|
||||
let List.287 : {} = Struct {};
|
||||
let List.286 : [C {}, C I64] = Err List.287;
|
||||
ret List.286;
|
||||
|
||||
procedure List.6 (#Attr.2):
|
||||
let List.270 : U64 = lowlevel ListLen #Attr.2;
|
||||
ret List.270;
|
||||
let List.295 : U64 = lowlevel ListLen #Attr.2;
|
||||
ret List.295;
|
||||
|
||||
procedure List.60 (#Attr.2, #Attr.3):
|
||||
let List.269 : I64 = lowlevel ListGetUnsafe #Attr.2 #Attr.3;
|
||||
ret List.269;
|
||||
let List.294 : I64 = lowlevel ListGetUnsafe #Attr.2 #Attr.3;
|
||||
ret List.294;
|
||||
|
||||
procedure Num.22 (#Attr.2, #Attr.3):
|
||||
let Num.273 : Int1 = lowlevel NumLt #Attr.2 #Attr.3;
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
procedure List.6 (#Attr.2):
|
||||
let List.261 : U64 = lowlevel ListLen #Attr.2;
|
||||
ret List.261;
|
||||
let List.286 : U64 = lowlevel ListLen #Attr.2;
|
||||
ret List.286;
|
||||
|
||||
procedure List.6 (#Attr.2):
|
||||
let List.262 : U64 = lowlevel ListLen #Attr.2;
|
||||
ret List.262;
|
||||
let List.287 : U64 = lowlevel ListLen #Attr.2;
|
||||
ret List.287;
|
||||
|
||||
procedure Num.19 (#Attr.2, #Attr.3):
|
||||
let Num.273 : U64 = lowlevel NumAdd #Attr.2 #Attr.3;
|
||||
|
|
|
@ -1,38 +1,38 @@
|
|||
procedure List.2 (List.74, List.75):
|
||||
let List.267 : U64 = CallByName List.6 List.74;
|
||||
let List.263 : Int1 = CallByName Num.22 List.75 List.267;
|
||||
if List.263 then
|
||||
let List.265 : Str = CallByName List.60 List.74 List.75;
|
||||
let List.264 : [C {}, C Str] = Ok List.265;
|
||||
ret List.264;
|
||||
procedure List.2 (List.76, List.77):
|
||||
let List.292 : U64 = CallByName List.6 List.76;
|
||||
let List.288 : Int1 = CallByName Num.22 List.77 List.292;
|
||||
if List.288 then
|
||||
let List.290 : Str = CallByName List.60 List.76 List.77;
|
||||
let List.289 : [C {}, C Str] = Ok List.290;
|
||||
ret List.289;
|
||||
else
|
||||
let List.262 : {} = Struct {};
|
||||
let List.261 : [C {}, C Str] = Err List.262;
|
||||
ret List.261;
|
||||
let List.287 : {} = Struct {};
|
||||
let List.286 : [C {}, C Str] = Err List.287;
|
||||
ret List.286;
|
||||
|
||||
procedure List.5 (#Attr.2, #Attr.3):
|
||||
let List.269 : List Str = lowlevel ListMap { xs: `#Attr.#arg1` } #Attr.2 Test.3 #Attr.3;
|
||||
ret List.269;
|
||||
let List.294 : List Str = lowlevel ListMap { xs: `#Attr.#arg1` } #Attr.2 Test.3 #Attr.3;
|
||||
ret List.294;
|
||||
|
||||
procedure List.6 (#Attr.2):
|
||||
let List.271 : U64 = lowlevel ListLen #Attr.2;
|
||||
ret List.271;
|
||||
let List.296 : U64 = lowlevel ListLen #Attr.2;
|
||||
ret List.296;
|
||||
|
||||
procedure List.60 (#Attr.2, #Attr.3):
|
||||
let List.270 : Str = lowlevel ListGetUnsafe #Attr.2 #Attr.3;
|
||||
ret List.270;
|
||||
let List.295 : Str = lowlevel ListGetUnsafe #Attr.2 #Attr.3;
|
||||
ret List.295;
|
||||
|
||||
procedure Num.22 (#Attr.2, #Attr.3):
|
||||
let Num.273 : Int1 = lowlevel NumLt #Attr.2 #Attr.3;
|
||||
ret Num.273;
|
||||
|
||||
procedure Str.16 (#Attr.2, #Attr.3):
|
||||
let Str.65 : Str = lowlevel StrRepeat #Attr.2 #Attr.3;
|
||||
ret Str.65;
|
||||
let Str.67 : Str = lowlevel StrRepeat #Attr.2 #Attr.3;
|
||||
ret Str.67;
|
||||
|
||||
procedure Str.3 (#Attr.2, #Attr.3):
|
||||
let Str.66 : Str = lowlevel StrConcat #Attr.2 #Attr.3;
|
||||
ret Str.66;
|
||||
let Str.68 : Str = lowlevel StrConcat #Attr.2 #Attr.3;
|
||||
ret Str.68;
|
||||
|
||||
procedure Test.1 ():
|
||||
let Test.21 : Str = "lllllllllllllllllllllooooooooooong";
|
||||
|
|
|
@ -1,36 +1,36 @@
|
|||
procedure List.2 (List.74, List.75):
|
||||
let List.267 : U64 = CallByName List.6 List.74;
|
||||
let List.263 : Int1 = CallByName Num.22 List.75 List.267;
|
||||
if List.263 then
|
||||
let List.265 : Str = CallByName List.60 List.74 List.75;
|
||||
let List.264 : [C {}, C Str] = Ok List.265;
|
||||
ret List.264;
|
||||
procedure List.2 (List.76, List.77):
|
||||
let List.292 : U64 = CallByName List.6 List.76;
|
||||
let List.288 : Int1 = CallByName Num.22 List.77 List.292;
|
||||
if List.288 then
|
||||
let List.290 : Str = CallByName List.60 List.76 List.77;
|
||||
let List.289 : [C {}, C Str] = Ok List.290;
|
||||
ret List.289;
|
||||
else
|
||||
let List.262 : {} = Struct {};
|
||||
let List.261 : [C {}, C Str] = Err List.262;
|
||||
ret List.261;
|
||||
let List.287 : {} = Struct {};
|
||||
let List.286 : [C {}, C Str] = Err List.287;
|
||||
ret List.286;
|
||||
|
||||
procedure List.5 (#Attr.2, #Attr.3):
|
||||
inc #Attr.2;
|
||||
let List.269 : List Str = lowlevel ListMap { xs: `#Attr.#arg1` } #Attr.2 Test.3 #Attr.3;
|
||||
let List.294 : List Str = lowlevel ListMap { xs: `#Attr.#arg1` } #Attr.2 Test.3 #Attr.3;
|
||||
decref #Attr.2;
|
||||
ret List.269;
|
||||
ret List.294;
|
||||
|
||||
procedure List.6 (#Attr.2):
|
||||
let List.271 : U64 = lowlevel ListLen #Attr.2;
|
||||
ret List.271;
|
||||
let List.296 : U64 = lowlevel ListLen #Attr.2;
|
||||
ret List.296;
|
||||
|
||||
procedure List.60 (#Attr.2, #Attr.3):
|
||||
let List.270 : Str = lowlevel ListGetUnsafe #Attr.2 #Attr.3;
|
||||
ret List.270;
|
||||
let List.295 : Str = lowlevel ListGetUnsafe #Attr.2 #Attr.3;
|
||||
ret List.295;
|
||||
|
||||
procedure Num.22 (#Attr.2, #Attr.3):
|
||||
let Num.273 : Int1 = lowlevel NumLt #Attr.2 #Attr.3;
|
||||
ret Num.273;
|
||||
|
||||
procedure Str.3 (#Attr.2, #Attr.3):
|
||||
let Str.66 : Str = lowlevel StrConcat #Attr.2 #Attr.3;
|
||||
ret Str.66;
|
||||
let Str.68 : Str = lowlevel StrConcat #Attr.2 #Attr.3;
|
||||
ret Str.68;
|
||||
|
||||
procedure Test.1 ():
|
||||
let Test.21 : Str = "lllllllllllllllllllllooooooooooong";
|
||||
|
|
|
@ -1,27 +1,27 @@
|
|||
procedure List.3 (List.83, List.84, List.85):
|
||||
let List.262 : {List I64, I64} = CallByName List.57 List.83 List.84 List.85;
|
||||
let List.261 : List I64 = StructAtIndex 0 List.262;
|
||||
inc List.261;
|
||||
dec List.262;
|
||||
ret List.261;
|
||||
procedure List.3 (List.85, List.86, List.87):
|
||||
let List.287 : {List I64, I64} = CallByName List.57 List.85 List.86 List.87;
|
||||
let List.286 : List I64 = StructAtIndex 0 List.287;
|
||||
inc List.286;
|
||||
dec List.287;
|
||||
ret List.286;
|
||||
|
||||
procedure List.57 (List.80, List.81, List.82):
|
||||
let List.268 : U64 = CallByName List.6 List.80;
|
||||
let List.265 : Int1 = CallByName Num.22 List.81 List.268;
|
||||
if List.265 then
|
||||
let List.266 : {List I64, I64} = CallByName List.61 List.80 List.81 List.82;
|
||||
ret List.266;
|
||||
procedure List.57 (List.82, List.83, List.84):
|
||||
let List.293 : U64 = CallByName List.6 List.82;
|
||||
let List.290 : Int1 = CallByName Num.22 List.83 List.293;
|
||||
if List.290 then
|
||||
let List.291 : {List I64, I64} = CallByName List.61 List.82 List.83 List.84;
|
||||
ret List.291;
|
||||
else
|
||||
let List.264 : {List I64, I64} = Struct {List.80, List.82};
|
||||
ret List.264;
|
||||
let List.289 : {List I64, I64} = Struct {List.82, List.84};
|
||||
ret List.289;
|
||||
|
||||
procedure List.6 (#Attr.2):
|
||||
let List.269 : U64 = lowlevel ListLen #Attr.2;
|
||||
ret List.269;
|
||||
let List.294 : U64 = lowlevel ListLen #Attr.2;
|
||||
ret List.294;
|
||||
|
||||
procedure List.61 (#Attr.2, #Attr.3, #Attr.4):
|
||||
let List.267 : {List I64, I64} = lowlevel ListReplaceUnsafe #Attr.2 #Attr.3 #Attr.4;
|
||||
ret List.267;
|
||||
let List.292 : {List I64, I64} = lowlevel ListReplaceUnsafe #Attr.2 #Attr.3 #Attr.4;
|
||||
ret List.292;
|
||||
|
||||
procedure Num.22 (#Attr.2, #Attr.3):
|
||||
let Num.273 : Int1 = lowlevel NumLt #Attr.2 #Attr.3;
|
||||
|
|
|
@ -1,16 +1,16 @@
|
|||
procedure List.28 (#Attr.2, #Attr.3):
|
||||
let List.264 : List I64 = lowlevel ListSortWith { xs: `#Attr.#arg1` } #Attr.2 Num.46 #Attr.3;
|
||||
let List.289 : List I64 = lowlevel ListSortWith { xs: `#Attr.#arg1` } #Attr.2 Num.46 #Attr.3;
|
||||
let Bool.14 : Int1 = lowlevel ListIsUnique #Attr.2;
|
||||
if Bool.14 then
|
||||
ret List.264;
|
||||
ret List.289;
|
||||
else
|
||||
decref #Attr.2;
|
||||
ret List.264;
|
||||
ret List.289;
|
||||
|
||||
procedure List.54 (List.179):
|
||||
let List.262 : {} = Struct {};
|
||||
let List.261 : List I64 = CallByName List.28 List.179 List.262;
|
||||
ret List.261;
|
||||
procedure List.54 (List.197):
|
||||
let List.287 : {} = Struct {};
|
||||
let List.286 : List I64 = CallByName List.28 List.197 List.287;
|
||||
ret List.286;
|
||||
|
||||
procedure Num.46 (#Attr.2, #Attr.3):
|
||||
let Num.273 : U8 = lowlevel NumCompare #Attr.2 #Attr.3;
|
||||
|
|
|
@ -1,21 +0,0 @@
|
|||
procedure Num.19 (#Attr.2, #Attr.3):
|
||||
let Num.273 : U64 = lowlevel NumAdd #Attr.2 #Attr.3;
|
||||
ret Num.273;
|
||||
|
||||
procedure Test.5 (Test.7, Test.8):
|
||||
let Test.17 : U64 = 1i64;
|
||||
ret Test.17;
|
||||
|
||||
procedure Test.6 (Test.7, Test.8):
|
||||
let Test.14 : U64 = 1i64;
|
||||
ret Test.14;
|
||||
|
||||
procedure Test.0 ():
|
||||
let Test.15 : U8 = 100i64;
|
||||
let Test.16 : U32 = 100i64;
|
||||
let Test.10 : U64 = CallByName Test.5 Test.15 Test.16;
|
||||
let Test.12 : U32 = 100i64;
|
||||
let Test.13 : U8 = 100i64;
|
||||
let Test.11 : U64 = CallByName Test.6 Test.12 Test.13;
|
||||
let Test.9 : U64 = CallByName Num.19 Test.10 Test.11;
|
||||
ret Test.9;
|
|
@ -1,43 +1,43 @@
|
|||
procedure List.2 (List.74, List.75):
|
||||
let List.281 : U64 = CallByName List.6 List.74;
|
||||
let List.277 : Int1 = CallByName Num.22 List.75 List.281;
|
||||
if List.277 then
|
||||
let List.279 : I64 = CallByName List.60 List.74 List.75;
|
||||
let List.278 : [C {}, C I64] = Ok List.279;
|
||||
ret List.278;
|
||||
procedure List.2 (List.76, List.77):
|
||||
let List.306 : U64 = CallByName List.6 List.76;
|
||||
let List.302 : Int1 = CallByName Num.22 List.77 List.306;
|
||||
if List.302 then
|
||||
let List.304 : I64 = CallByName List.60 List.76 List.77;
|
||||
let List.303 : [C {}, C I64] = Ok List.304;
|
||||
ret List.303;
|
||||
else
|
||||
let List.276 : {} = Struct {};
|
||||
let List.275 : [C {}, C I64] = Err List.276;
|
||||
ret List.275;
|
||||
let List.301 : {} = Struct {};
|
||||
let List.300 : [C {}, C I64] = Err List.301;
|
||||
ret List.300;
|
||||
|
||||
procedure List.3 (List.83, List.84, List.85):
|
||||
let List.265 : {List I64, I64} = CallByName List.57 List.83 List.84 List.85;
|
||||
let List.264 : List I64 = StructAtIndex 0 List.265;
|
||||
inc List.264;
|
||||
dec List.265;
|
||||
ret List.264;
|
||||
|
||||
procedure List.57 (List.80, List.81, List.82):
|
||||
let List.287 : U64 = CallByName List.6 List.80;
|
||||
let List.284 : Int1 = CallByName Num.22 List.81 List.287;
|
||||
if List.284 then
|
||||
let List.285 : {List I64, I64} = CallByName List.61 List.80 List.81 List.82;
|
||||
ret List.285;
|
||||
else
|
||||
let List.283 : {List I64, I64} = Struct {List.80, List.82};
|
||||
ret List.283;
|
||||
|
||||
procedure List.6 (#Attr.2):
|
||||
let List.288 : U64 = lowlevel ListLen #Attr.2;
|
||||
ret List.288;
|
||||
|
||||
procedure List.60 (#Attr.2, #Attr.3):
|
||||
let List.289 : I64 = lowlevel ListGetUnsafe #Attr.2 #Attr.3;
|
||||
procedure List.3 (List.85, List.86, List.87):
|
||||
let List.290 : {List I64, I64} = CallByName List.57 List.85 List.86 List.87;
|
||||
let List.289 : List I64 = StructAtIndex 0 List.290;
|
||||
inc List.289;
|
||||
dec List.290;
|
||||
ret List.289;
|
||||
|
||||
procedure List.57 (List.82, List.83, List.84):
|
||||
let List.312 : U64 = CallByName List.6 List.82;
|
||||
let List.309 : Int1 = CallByName Num.22 List.83 List.312;
|
||||
if List.309 then
|
||||
let List.310 : {List I64, I64} = CallByName List.61 List.82 List.83 List.84;
|
||||
ret List.310;
|
||||
else
|
||||
let List.308 : {List I64, I64} = Struct {List.82, List.84};
|
||||
ret List.308;
|
||||
|
||||
procedure List.6 (#Attr.2):
|
||||
let List.313 : U64 = lowlevel ListLen #Attr.2;
|
||||
ret List.313;
|
||||
|
||||
procedure List.60 (#Attr.2, #Attr.3):
|
||||
let List.314 : I64 = lowlevel ListGetUnsafe #Attr.2 #Attr.3;
|
||||
ret List.314;
|
||||
|
||||
procedure List.61 (#Attr.2, #Attr.3, #Attr.4):
|
||||
let List.286 : {List I64, I64} = lowlevel ListReplaceUnsafe #Attr.2 #Attr.3 #Attr.4;
|
||||
ret List.286;
|
||||
let List.311 : {List I64, I64} = lowlevel ListReplaceUnsafe #Attr.2 #Attr.3 #Attr.4;
|
||||
ret List.311;
|
||||
|
||||
procedure Num.22 (#Attr.2, #Attr.3):
|
||||
let Num.275 : Int1 = lowlevel NumLt #Attr.2 #Attr.3;
|
||||
|
|
|
@ -1,43 +1,43 @@
|
|||
procedure List.2 (List.74, List.75):
|
||||
let List.281 : U64 = CallByName List.6 List.74;
|
||||
let List.277 : Int1 = CallByName Num.22 List.75 List.281;
|
||||
if List.277 then
|
||||
let List.279 : I64 = CallByName List.60 List.74 List.75;
|
||||
let List.278 : [C {}, C I64] = Ok List.279;
|
||||
ret List.278;
|
||||
procedure List.2 (List.76, List.77):
|
||||
let List.306 : U64 = CallByName List.6 List.76;
|
||||
let List.302 : Int1 = CallByName Num.22 List.77 List.306;
|
||||
if List.302 then
|
||||
let List.304 : I64 = CallByName List.60 List.76 List.77;
|
||||
let List.303 : [C {}, C I64] = Ok List.304;
|
||||
ret List.303;
|
||||
else
|
||||
let List.276 : {} = Struct {};
|
||||
let List.275 : [C {}, C I64] = Err List.276;
|
||||
ret List.275;
|
||||
let List.301 : {} = Struct {};
|
||||
let List.300 : [C {}, C I64] = Err List.301;
|
||||
ret List.300;
|
||||
|
||||
procedure List.3 (List.83, List.84, List.85):
|
||||
let List.265 : {List I64, I64} = CallByName List.57 List.83 List.84 List.85;
|
||||
let List.264 : List I64 = StructAtIndex 0 List.265;
|
||||
inc List.264;
|
||||
dec List.265;
|
||||
ret List.264;
|
||||
|
||||
procedure List.57 (List.80, List.81, List.82):
|
||||
let List.287 : U64 = CallByName List.6 List.80;
|
||||
let List.284 : Int1 = CallByName Num.22 List.81 List.287;
|
||||
if List.284 then
|
||||
let List.285 : {List I64, I64} = CallByName List.61 List.80 List.81 List.82;
|
||||
ret List.285;
|
||||
else
|
||||
let List.283 : {List I64, I64} = Struct {List.80, List.82};
|
||||
ret List.283;
|
||||
|
||||
procedure List.6 (#Attr.2):
|
||||
let List.288 : U64 = lowlevel ListLen #Attr.2;
|
||||
ret List.288;
|
||||
|
||||
procedure List.60 (#Attr.2, #Attr.3):
|
||||
let List.289 : I64 = lowlevel ListGetUnsafe #Attr.2 #Attr.3;
|
||||
procedure List.3 (List.85, List.86, List.87):
|
||||
let List.290 : {List I64, I64} = CallByName List.57 List.85 List.86 List.87;
|
||||
let List.289 : List I64 = StructAtIndex 0 List.290;
|
||||
inc List.289;
|
||||
dec List.290;
|
||||
ret List.289;
|
||||
|
||||
procedure List.57 (List.82, List.83, List.84):
|
||||
let List.312 : U64 = CallByName List.6 List.82;
|
||||
let List.309 : Int1 = CallByName Num.22 List.83 List.312;
|
||||
if List.309 then
|
||||
let List.310 : {List I64, I64} = CallByName List.61 List.82 List.83 List.84;
|
||||
ret List.310;
|
||||
else
|
||||
let List.308 : {List I64, I64} = Struct {List.82, List.84};
|
||||
ret List.308;
|
||||
|
||||
procedure List.6 (#Attr.2):
|
||||
let List.313 : U64 = lowlevel ListLen #Attr.2;
|
||||
ret List.313;
|
||||
|
||||
procedure List.60 (#Attr.2, #Attr.3):
|
||||
let List.314 : I64 = lowlevel ListGetUnsafe #Attr.2 #Attr.3;
|
||||
ret List.314;
|
||||
|
||||
procedure List.61 (#Attr.2, #Attr.3, #Attr.4):
|
||||
let List.286 : {List I64, I64} = lowlevel ListReplaceUnsafe #Attr.2 #Attr.3 #Attr.4;
|
||||
ret List.286;
|
||||
let List.311 : {List I64, I64} = lowlevel ListReplaceUnsafe #Attr.2 #Attr.3 #Attr.4;
|
||||
ret List.311;
|
||||
|
||||
procedure Num.22 (#Attr.2, #Attr.3):
|
||||
let Num.275 : Int1 = lowlevel NumLt #Attr.2 #Attr.3;
|
||||
|
|
|
@ -1,53 +0,0 @@
|
|||
procedure Num.19 (#Attr.2, #Attr.3):
|
||||
let Num.274 : I64 = lowlevel NumAdd #Attr.2 #Attr.3;
|
||||
ret Num.274;
|
||||
|
||||
procedure Num.21 (#Attr.2, #Attr.3):
|
||||
let Num.273 : I64 = lowlevel NumMul #Attr.2 #Attr.3;
|
||||
ret Num.273;
|
||||
|
||||
procedure Test.1 ():
|
||||
let Test.26 : I64 = 1i64;
|
||||
ret Test.26;
|
||||
|
||||
procedure Test.2 ():
|
||||
let Test.22 : I64 = 2i64;
|
||||
ret Test.22;
|
||||
|
||||
procedure Test.3 (Test.6):
|
||||
let Test.25 : I64 = CallByName Test.1;
|
||||
let Test.24 : I64 = CallByName Num.19 Test.6 Test.25;
|
||||
ret Test.24;
|
||||
|
||||
procedure Test.4 (Test.7):
|
||||
let Test.21 : I64 = CallByName Test.2;
|
||||
let Test.20 : I64 = CallByName Num.21 Test.7 Test.21;
|
||||
ret Test.20;
|
||||
|
||||
procedure Test.5 (Test.8, Test.9):
|
||||
joinpoint Test.15 Test.14:
|
||||
ret Test.14;
|
||||
in
|
||||
switch Test.8:
|
||||
case 0:
|
||||
let Test.16 : I64 = CallByName Test.3 Test.9;
|
||||
jump Test.15 Test.16;
|
||||
|
||||
default:
|
||||
let Test.17 : I64 = CallByName Test.4 Test.9;
|
||||
jump Test.15 Test.17;
|
||||
|
||||
|
||||
procedure Test.0 ():
|
||||
joinpoint Test.19 Test.12:
|
||||
let Test.13 : I64 = 42i64;
|
||||
let Test.11 : I64 = CallByName Test.5 Test.12 Test.13;
|
||||
ret Test.11;
|
||||
in
|
||||
let Test.23 : Int1 = true;
|
||||
if Test.23 then
|
||||
let Test.3 : Int1 = false;
|
||||
jump Test.19 Test.3;
|
||||
else
|
||||
let Test.4 : Int1 = true;
|
||||
jump Test.19 Test.4;
|
Loading…
Add table
Add a link
Reference in a new issue