mirror of
https://github.com/roc-lang/roc.git
synced 2025-08-04 12:18:19 +00:00
Merge remote-tracking branch 'upstream' into annotate-type-signatures
This commit is contained in:
commit
4f7729c044
330 changed files with 10591 additions and 7447 deletions
|
@ -203,6 +203,7 @@ comptime {
|
|||
exportStrFn(str.reserveC, "reserve");
|
||||
exportStrFn(str.strToUtf8C, "to_utf8");
|
||||
exportStrFn(str.fromUtf8C, "from_utf8");
|
||||
exportStrFn(str.fromUtf8Lossy, "from_utf8_lossy");
|
||||
exportStrFn(str.repeatC, "repeat");
|
||||
exportStrFn(str.strTrim, "trim");
|
||||
exportStrFn(str.strTrimStart, "trim_start");
|
||||
|
@ -211,6 +212,9 @@ comptime {
|
|||
exportStrFn(str.withCapacityC, "with_capacity");
|
||||
exportStrFn(str.strAllocationPtr, "allocation_ptr");
|
||||
exportStrFn(str.strReleaseExcessCapacity, "release_excess_capacity");
|
||||
exportStrFn(str.strWithAsciiLowercased, "with_ascii_lowercased");
|
||||
exportStrFn(str.strWithAsciiUppercased, "with_ascii_uppercased");
|
||||
exportStrFn(str.strCaselessAsciiEquals, "caseless_ascii_equals");
|
||||
|
||||
for (INTEGERS) |T| {
|
||||
str.exportFromInt(T, ROC_BUILTINS ++ "." ++ STR ++ ".from_int.");
|
||||
|
|
|
@ -2,6 +2,7 @@ const utils = @import("utils.zig");
|
|||
const RocList = @import("list.zig").RocList;
|
||||
const UpdateMode = utils.UpdateMode;
|
||||
const std = @import("std");
|
||||
const ascii = std.ascii;
|
||||
const mem = std.mem;
|
||||
const unicode = std.unicode;
|
||||
const testing = std.testing;
|
||||
|
@ -178,7 +179,7 @@ pub const RocStr = extern struct {
|
|||
|
||||
pub fn eq(self: RocStr, other: RocStr) bool {
|
||||
// If they are byte-for-byte equal, they're definitely equal!
|
||||
if (self.bytes == other.bytes and self.length == other.length and self.capacity_or_alloc_ptr == other.capacity_or_alloc_ptr) {
|
||||
if (self.bytes == other.bytes and self.length == other.length) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -370,11 +371,17 @@ pub const RocStr = extern struct {
|
|||
}
|
||||
|
||||
fn refcount(self: RocStr) usize {
|
||||
if ((self.getCapacity() == 0 and !self.isSeamlessSlice()) or self.isSmallStr()) {
|
||||
const is_seamless_slice = self.isSeamlessSlice();
|
||||
if ((self.getCapacity() == 0 and !is_seamless_slice) or self.isSmallStr()) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
const ptr: [*]usize = @as([*]usize, @ptrCast(@alignCast(self.bytes)));
|
||||
const data_ptr = if (is_seamless_slice)
|
||||
self.getAllocationPtr()
|
||||
else
|
||||
self.bytes;
|
||||
|
||||
const ptr: [*]usize = @as([*]usize, @ptrCast(@alignCast(data_ptr)));
|
||||
return (ptr - 1)[0];
|
||||
}
|
||||
|
||||
|
@ -611,16 +618,6 @@ fn initFromSmallStr(slice_bytes: [*]u8, len: usize, _: usize) RocStr {
|
|||
return RocStr.init(slice_bytes, len);
|
||||
}
|
||||
|
||||
// The alloc_ptr must already be shifted to be ready for storing in a seamless slice.
|
||||
fn initFromBigStr(slice_bytes: [*]u8, len: usize, alloc_ptr: usize) RocStr {
|
||||
// Here we can make seamless slices instead of copying to a new small str.
|
||||
return RocStr{
|
||||
.bytes = slice_bytes,
|
||||
.length = len | SEAMLESS_SLICE_BIT,
|
||||
.capacity_or_alloc_ptr = alloc_ptr,
|
||||
};
|
||||
}
|
||||
|
||||
fn strSplitOnHelp(array: [*]RocStr, string: RocStr, delimiter: RocStr) void {
|
||||
if (delimiter.len() == 0) {
|
||||
string.incref(1);
|
||||
|
@ -1449,6 +1446,105 @@ pub fn fromUtf8C(
|
|||
return fromUtf8(list, update_mode);
|
||||
}
|
||||
|
||||
const UNICODE_REPLACEMENT: u21 = 0xfffd;
|
||||
|
||||
const Utf8Iterator = struct {
|
||||
bytes: []u8,
|
||||
i: usize,
|
||||
|
||||
pub fn init(list: RocList) Utf8Iterator {
|
||||
const bytes = @as([*]u8, @ptrCast(list.bytes))[0..list.length];
|
||||
return Utf8Iterator{
|
||||
.bytes = bytes,
|
||||
.i = 0,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn nextLossy(it: *Utf8Iterator) ?u32 {
|
||||
if (it.bytes.len <= it.i) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const rest = it.bytes[it.i..];
|
||||
const n = unicode.utf8ByteSequenceLength(rest[0]) catch {
|
||||
// invalid start byte
|
||||
it.i += 1;
|
||||
return UNICODE_REPLACEMENT;
|
||||
};
|
||||
|
||||
for (1..n) |i| {
|
||||
if (rest.len == i) {
|
||||
// unexpected end
|
||||
it.i += i;
|
||||
return UNICODE_REPLACEMENT;
|
||||
}
|
||||
if (rest[i] < 0x70) {
|
||||
// expected continuation byte (>= 0x70)
|
||||
it.i += i;
|
||||
return UNICODE_REPLACEMENT;
|
||||
}
|
||||
}
|
||||
|
||||
it.i += n;
|
||||
return unicode.utf8Decode(rest[0..n]) catch {
|
||||
return UNICODE_REPLACEMENT;
|
||||
};
|
||||
}
|
||||
|
||||
pub fn reset(it: *Utf8Iterator) void {
|
||||
it.i = 0;
|
||||
}
|
||||
};
|
||||
|
||||
fn codepointSeqLengthLossy(c: u32) u3 {
|
||||
if (c < 0x110000) {
|
||||
if (unicode.utf8CodepointSequenceLength(@intCast(c))) |n| {
|
||||
return n;
|
||||
} else |_| {
|
||||
// fallthrough
|
||||
}
|
||||
}
|
||||
return unicode.utf8CodepointSequenceLength(UNICODE_REPLACEMENT) catch unreachable;
|
||||
}
|
||||
|
||||
fn utf8EncodeLossy(c: u32, out: []u8) u3 {
|
||||
if (c < 0x110000) {
|
||||
if (unicode.utf8Encode(@intCast(c), out)) |n| {
|
||||
return n;
|
||||
} else |_| {
|
||||
// fallthrough
|
||||
}
|
||||
}
|
||||
return unicode.utf8Encode(UNICODE_REPLACEMENT, out) catch unreachable;
|
||||
}
|
||||
|
||||
pub fn fromUtf8Lossy(
|
||||
list: RocList,
|
||||
) callconv(.C) RocStr {
|
||||
if (list.len() == 0) {
|
||||
return RocStr.empty();
|
||||
}
|
||||
|
||||
// PERF: we could try to reuse the input list if it's already valid utf-8, similar to fromUtf8
|
||||
|
||||
var it = Utf8Iterator.init(list);
|
||||
|
||||
var enc_len: usize = 0;
|
||||
while (it.nextLossy()) |c| {
|
||||
enc_len += codepointSeqLengthLossy(c);
|
||||
}
|
||||
|
||||
var str = RocStr.allocate(enc_len);
|
||||
const ptr = str.asU8ptrMut()[0..enc_len];
|
||||
var end_index: usize = 0;
|
||||
it.reset();
|
||||
while (it.nextLossy()) |c| {
|
||||
end_index += utf8EncodeLossy(c, ptr[end_index..]);
|
||||
}
|
||||
str.setLen(end_index);
|
||||
return str;
|
||||
}
|
||||
|
||||
pub fn fromUtf8(
|
||||
list: RocList,
|
||||
update_mode: UpdateMode,
|
||||
|
@ -1667,6 +1763,17 @@ test "validateUtf8Bytes: unicode ∆ in middle of array" {
|
|||
try expectOk(str_result);
|
||||
}
|
||||
|
||||
test "fromUtf8Lossy: ascii, emoji" {
|
||||
var list = RocList.fromSlice(u8, "r💖c", false);
|
||||
defer list.decref(@alignOf(u8), @sizeOf(u8), false, rcNone);
|
||||
|
||||
const res = fromUtf8Lossy(list);
|
||||
defer res.decref();
|
||||
const expected = RocStr.fromSlice("r💖c");
|
||||
defer expected.decref();
|
||||
try expect(expected.eq(res));
|
||||
}
|
||||
|
||||
fn expectErr(list: RocList, index: usize, err: Utf8DecodeError, problem: Utf8ByteProblem) !void {
|
||||
const str_ptr = @as([*]u8, @ptrCast(list.bytes));
|
||||
const len = list.length;
|
||||
|
@ -1765,6 +1872,66 @@ test "validateUtf8Bytes: surrogate halves" {
|
|||
try expectErr(list, 3, error.Utf8EncodesSurrogateHalf, Utf8ByteProblem.EncodesSurrogateHalf);
|
||||
}
|
||||
|
||||
test "fromUtf8Lossy: invalid start byte" {
|
||||
var list = RocList.fromSlice(u8, "r\x80c", false);
|
||||
defer list.decref(@alignOf(u8), @sizeOf(u8), false, rcNone);
|
||||
|
||||
const res = fromUtf8Lossy(list);
|
||||
defer res.decref();
|
||||
const expected = RocStr.fromSlice("r<EFBFBD>c");
|
||||
defer expected.decref();
|
||||
try expect(expected.eq(res));
|
||||
}
|
||||
|
||||
test "fromUtf8Lossy: overlong encoding" {
|
||||
var list = RocList.fromSlice(u8, "r\xF0\x9F\x92\x96\x80c", false);
|
||||
defer list.decref(@alignOf(u8), @sizeOf(u8), false, rcNone);
|
||||
|
||||
const res = fromUtf8Lossy(list);
|
||||
defer res.decref();
|
||||
const expected = RocStr.fromSlice("r💖<EFBFBD>c");
|
||||
defer expected.decref();
|
||||
try expect(expected.eq(res));
|
||||
}
|
||||
|
||||
test "fromUtf8Lossy: expected continuation" {
|
||||
var list = RocList.fromSlice(u8, "r\xCFc", false);
|
||||
defer list.decref(@alignOf(u8), @sizeOf(u8), false, rcNone);
|
||||
|
||||
const res = fromUtf8Lossy(list);
|
||||
defer res.decref();
|
||||
const expected = RocStr.fromSlice("r<EFBFBD>c");
|
||||
defer expected.decref();
|
||||
try expect(expected.eq(res));
|
||||
}
|
||||
|
||||
test "fromUtf8Lossy: unexpected end" {
|
||||
var list = RocList.fromSlice(u8, "r\xCF", false);
|
||||
defer list.decref(@alignOf(u8), @sizeOf(u8), false, rcNone);
|
||||
|
||||
const res = fromUtf8Lossy(list);
|
||||
defer res.decref();
|
||||
const expected = RocStr.fromSlice("r<EFBFBD>");
|
||||
defer expected.decref();
|
||||
try expect(expected.eq(res));
|
||||
}
|
||||
|
||||
test "fromUtf8Lossy: encodes surrogate" {
|
||||
// 0xd83d == 0b1101_1000_0011_1101
|
||||
// wwww xxxx yyyy zzzz
|
||||
// becomes 0b1110_1101 0b10_1000_00 0b10_11_1101
|
||||
// 1110_wwww 10_xxxx_yy 10_yy_zzzz
|
||||
// 0xED 0x90 0xBD
|
||||
var list = RocList.fromSlice(u8, "r\xED\xA0\xBDc", false);
|
||||
defer list.decref(@alignOf(u8), @sizeOf(u8), false, rcNone);
|
||||
|
||||
const res = fromUtf8Lossy(list);
|
||||
defer res.decref();
|
||||
const expected = RocStr.fromSlice("r<EFBFBD>c");
|
||||
defer expected.decref();
|
||||
try expect(expected.eq(res));
|
||||
}
|
||||
|
||||
fn isWhitespace(codepoint: u21) bool {
|
||||
// https://www.unicode.org/Public/UCD/latest/ucd/PropList.txt
|
||||
return switch (codepoint) {
|
||||
|
@ -1968,6 +2135,194 @@ fn countTrailingWhitespaceBytes(string: RocStr) usize {
|
|||
return byte_count;
|
||||
}
|
||||
|
||||
// Str.with_ascii_lowercased
|
||||
pub fn strWithAsciiLowercased(string: RocStr) callconv(.C) RocStr {
|
||||
var new_str = if (string.isUnique())
|
||||
string
|
||||
else blk: {
|
||||
string.decref();
|
||||
break :blk RocStr.fromSlice(string.asSlice());
|
||||
};
|
||||
|
||||
const new_str_bytes = new_str.asU8ptrMut()[0..string.len()];
|
||||
for (new_str_bytes) |*c| {
|
||||
c.* = ascii.toLower(c.*);
|
||||
}
|
||||
return new_str;
|
||||
}
|
||||
|
||||
test "withAsciiLowercased: small str" {
|
||||
const original = RocStr.fromSlice("cOFFÉ");
|
||||
try expect(original.isSmallStr());
|
||||
|
||||
const expected = RocStr.fromSlice("coffÉ");
|
||||
defer expected.decref();
|
||||
|
||||
const str_result = strWithAsciiLowercased(original);
|
||||
defer str_result.decref();
|
||||
|
||||
try expect(str_result.isSmallStr());
|
||||
try expect(str_result.eq(expected));
|
||||
}
|
||||
|
||||
test "withAsciiLowercased: non small str" {
|
||||
const original = RocStr.fromSlice("cOFFÉ cOFFÉ cOFFÉ cOFFÉ cOFFÉ cOFFÉ");
|
||||
defer original.decref();
|
||||
try expect(!original.isSmallStr());
|
||||
|
||||
const expected = RocStr.fromSlice("coffÉ coffÉ coffÉ coffÉ coffÉ coffÉ");
|
||||
defer expected.decref();
|
||||
|
||||
const str_result = strWithAsciiLowercased(original);
|
||||
|
||||
try expect(!str_result.isSmallStr());
|
||||
try expect(str_result.eq(expected));
|
||||
}
|
||||
|
||||
test "withAsciiLowercased: seamless slice" {
|
||||
const l = RocStr.fromSlice("cOFFÉ cOFFÉ cOFFÉ cOFFÉ cOFFÉ cOFFÉ");
|
||||
const original = substringUnsafeC(l, 1, l.len() - 1);
|
||||
defer original.decref();
|
||||
|
||||
try expect(original.isSeamlessSlice());
|
||||
|
||||
const expected = RocStr.fromSlice("offÉ coffÉ coffÉ coffÉ coffÉ coffÉ");
|
||||
defer expected.decref();
|
||||
|
||||
const str_result = strWithAsciiLowercased(original);
|
||||
|
||||
try expect(!str_result.isSmallStr());
|
||||
try expect(str_result.eq(expected));
|
||||
}
|
||||
|
||||
// Str.with_ascii_uppercased
|
||||
pub fn strWithAsciiUppercased(string: RocStr) callconv(.C) RocStr {
|
||||
var new_str = if (string.isUnique())
|
||||
string
|
||||
else blk: {
|
||||
string.decref();
|
||||
break :blk RocStr.fromSlice(string.asSlice());
|
||||
};
|
||||
|
||||
const new_str_bytes = new_str.asU8ptrMut()[0..string.len()];
|
||||
for (new_str_bytes) |*c| {
|
||||
c.* = ascii.toUpper(c.*);
|
||||
}
|
||||
return new_str;
|
||||
}
|
||||
|
||||
test "withAsciiUppercased: small str" {
|
||||
const original = RocStr.fromSlice("coffé");
|
||||
try expect(original.isSmallStr());
|
||||
|
||||
const expected = RocStr.fromSlice("COFFé");
|
||||
defer expected.decref();
|
||||
|
||||
const str_result = strWithAsciiUppercased(original);
|
||||
defer str_result.decref();
|
||||
|
||||
try expect(str_result.isSmallStr());
|
||||
try expect(str_result.eq(expected));
|
||||
}
|
||||
|
||||
test "withAsciiUppercased: non small str" {
|
||||
const original = RocStr.fromSlice("coffé coffé coffé coffé coffé coffé");
|
||||
defer original.decref();
|
||||
try expect(!original.isSmallStr());
|
||||
|
||||
const expected = RocStr.fromSlice("COFFé COFFé COFFé COFFé COFFé COFFé");
|
||||
defer expected.decref();
|
||||
|
||||
const str_result = strWithAsciiUppercased(original);
|
||||
|
||||
try expect(!str_result.isSmallStr());
|
||||
try expect(str_result.eq(expected));
|
||||
}
|
||||
|
||||
test "withAsciiUppercased: seamless slice" {
|
||||
const l = RocStr.fromSlice("coffé coffé coffé coffé coffé coffé");
|
||||
const original = substringUnsafeC(l, 1, l.len() - 1);
|
||||
defer original.decref();
|
||||
|
||||
try expect(original.isSeamlessSlice());
|
||||
|
||||
const expected = RocStr.fromSlice("OFFé COFFé COFFé COFFé COFFé COFFé");
|
||||
defer expected.decref();
|
||||
|
||||
const str_result = strWithAsciiUppercased(original);
|
||||
|
||||
try expect(!str_result.isSmallStr());
|
||||
try expect(str_result.eq(expected));
|
||||
}
|
||||
|
||||
pub fn strCaselessAsciiEquals(self: RocStr, other: RocStr) callconv(.C) bool {
|
||||
if (self.bytes == other.bytes and self.length == other.length) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return ascii.eqlIgnoreCase(self.asSlice(), other.asSlice());
|
||||
}
|
||||
|
||||
test "caselessAsciiEquals: same str" {
|
||||
const str1 = RocStr.fromSlice("coFféÉ");
|
||||
defer str1.decref();
|
||||
|
||||
const are_equal = strCaselessAsciiEquals(str1, str1);
|
||||
try expect(are_equal);
|
||||
}
|
||||
|
||||
test "caselessAsciiEquals: differently capitalized non-ascii char" {
|
||||
const str1 = RocStr.fromSlice("coffé");
|
||||
defer str1.decref();
|
||||
try expect(str1.isSmallStr());
|
||||
|
||||
const str2 = RocStr.fromSlice("coffÉ");
|
||||
defer str2.decref();
|
||||
|
||||
const are_equal = strCaselessAsciiEquals(str1, str2);
|
||||
try expect(!are_equal);
|
||||
}
|
||||
|
||||
test "caselessAsciiEquals: small str" {
|
||||
const str1 = RocStr.fromSlice("coffé");
|
||||
defer str1.decref();
|
||||
try expect(str1.isSmallStr());
|
||||
|
||||
const str2 = RocStr.fromSlice("COFFé");
|
||||
defer str2.decref();
|
||||
|
||||
const are_equal = strCaselessAsciiEquals(str1, str2);
|
||||
try expect(are_equal);
|
||||
}
|
||||
|
||||
test "caselessAsciiEquals: non small str" {
|
||||
const str1 = RocStr.fromSlice("coffé coffé coffé coffé coffé coffé");
|
||||
defer str1.decref();
|
||||
try expect(!str1.isSmallStr());
|
||||
|
||||
const str2 = RocStr.fromSlice("COFFé COFFé COFFé COFFé COFFé COFFé");
|
||||
defer str2.decref();
|
||||
|
||||
const are_equal = strCaselessAsciiEquals(str1, str2);
|
||||
|
||||
try expect(are_equal);
|
||||
}
|
||||
|
||||
test "caselessAsciiEquals: seamless slice" {
|
||||
const l = RocStr.fromSlice("coffé coffé coffé coffé coffé coffé");
|
||||
const str1 = substringUnsafeC(l, 1, l.len() - 1);
|
||||
defer str1.decref();
|
||||
|
||||
try expect(str1.isSeamlessSlice());
|
||||
|
||||
const str2 = RocStr.fromSlice("OFFé COFFé COFFé COFFé COFFé COFFé");
|
||||
defer str2.decref();
|
||||
|
||||
const are_equal = strCaselessAsciiEquals(str1, str2);
|
||||
|
||||
try expect(are_equal);
|
||||
}
|
||||
|
||||
fn rcNone(_: ?[*]u8) callconv(.C) void {}
|
||||
|
||||
fn decStr(ptr: ?[*]u8) callconv(.C) void {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
module [Bool, Eq, true, false, and, or, not, is_eq, is_not_eq]
|
||||
module [Bool, Eq, true, false, not, is_eq, is_not_eq]
|
||||
|
||||
## Defines a type that can be compared for total equality.
|
||||
##
|
||||
|
@ -34,7 +34,7 @@ Eq implements
|
|||
## `Bool` implements the `Eq` ability.
|
||||
Bool := [True, False] implements [Eq { is_eq: bool_is_eq }]
|
||||
|
||||
bool_is_eq = \@Bool(b1), @Bool(b2) -> structural_eq(b1, b2)
|
||||
bool_is_eq = |@Bool(b1), @Bool(b2)| structural_eq(b1, b2)
|
||||
|
||||
## The boolean true value.
|
||||
true : Bool
|
||||
|
@ -44,55 +44,6 @@ true = @Bool(True)
|
|||
false : Bool
|
||||
false = @Bool(False)
|
||||
|
||||
## Returns `Bool.true` when both inputs are `Bool.true`. This is equivalent to
|
||||
## the logic [AND](https://en.wikipedia.org/wiki/Logical_conjunction)
|
||||
## gate. The infix operator `&&` can also be used as shorthand for
|
||||
## `Bool.and`.
|
||||
##
|
||||
## ```roc
|
||||
## expect Bool.and(Bool.true, Bool.true) == Bool.true
|
||||
## expect (Bool.true && Bool.true) == Bool.true
|
||||
## expect (Bool.false && Bool.true) == Bool.false
|
||||
## expect (Bool.true && Bool.false) == Bool.false
|
||||
## expect (Bool.false && Bool.false) == Bool.false
|
||||
## ```
|
||||
##
|
||||
## ## Performance Details
|
||||
##
|
||||
## In Roc the `&&` and `||` work the same way as any
|
||||
## other function. However, in some languages `&&` and `||` are special-cased.
|
||||
## In these languages the compiler will skip evaluating the expression after the
|
||||
## first operator under certain circumstances. For example an expression like
|
||||
## `enable_pets && likes_dogs(user)` would compile to.
|
||||
## ```roc
|
||||
## if enable_pets then
|
||||
## likes_dogs(user)
|
||||
## else
|
||||
## Bool.false
|
||||
## ```
|
||||
## Roc does not do this because conditionals like `if` and `when` have a
|
||||
## performance cost. Calling a function can sometimes be faster across the board
|
||||
## than doing an `if` to decide whether to skip calling it.
|
||||
and : Bool, Bool -> Bool
|
||||
|
||||
## Returns `Bool.true` when either input is a `Bool.true`. This is equivalent to
|
||||
## the logic [OR](https://en.wikipedia.org/wiki/Logical_disjunction) gate.
|
||||
## The infix operator `||` can also be used as shorthand for `Bool.or`.
|
||||
## ```roc
|
||||
## expect Bool.or(Bool.false, Bool.true) == Bool.true
|
||||
## expect (Bool.true || Bool.true) == Bool.true
|
||||
## expect (Bool.false || Bool.true) == Bool.true
|
||||
## expect (Bool.true || Bool.false) == Bool.true
|
||||
## expect (Bool.false || Bool.false) == Bool.false
|
||||
## ```
|
||||
##
|
||||
## ## Performance Details
|
||||
##
|
||||
## In Roc the `&&` and `||` work the same way as any
|
||||
## other functions. However, in some languages `&&` and `||` are special-cased.
|
||||
## Refer to the note in `Bool.and` for more detail.
|
||||
or : Bool, Bool -> Bool
|
||||
|
||||
## Returns `Bool.false` when given `Bool.true`, and vice versa. This is
|
||||
## equivalent to the logic [NOT](https://en.wikipedia.org/wiki/Negation)
|
||||
## gate. The operator `!` can also be used as shorthand for `Bool.not`.
|
||||
|
@ -115,7 +66,7 @@ not : Bool -> Bool
|
|||
## expect "Apples" != "Oranges"
|
||||
## ```
|
||||
is_not_eq : a, a -> Bool where a implements Eq
|
||||
is_not_eq = \a, b -> structural_not_eq(a, b)
|
||||
is_not_eq = |a, b| structural_not_eq(a, b)
|
||||
|
||||
# INTERNAL COMPILER USE ONLY: used to lower calls to `is_eq` to structural
|
||||
# equality via the `Eq` low-level for derived types.
|
||||
|
|
|
@ -123,11 +123,11 @@ DecoderFormatting implements
|
|||
## _ -> { result: Err(TooShort), rest: bytes }
|
||||
## ```
|
||||
custom : (List U8, fmt -> DecodeResult val) -> Decoder val fmt where fmt implements DecoderFormatting
|
||||
custom = \decode -> @Decoder(decode)
|
||||
custom = |decode| @Decoder(decode)
|
||||
|
||||
## Decode a `List U8` utf-8 bytes using a specific [Decoder] function
|
||||
decode_with : List U8, Decoder val fmt, fmt -> DecodeResult val where fmt implements DecoderFormatting
|
||||
decode_with = \bytes, @Decoder(decode), fmt -> decode(bytes, fmt)
|
||||
decode_with = |bytes, @Decoder(decode), fmt| decode(bytes, fmt)
|
||||
|
||||
## Decode a `List U8` utf-8 bytes and return a [DecodeResult](#DecodeResult)
|
||||
## ```roc
|
||||
|
@ -139,7 +139,7 @@ decode_with = \bytes, @Decoder(decode), fmt -> decode(bytes, fmt)
|
|||
## actual.result == expected
|
||||
## ```
|
||||
from_bytes_partial : List U8, fmt -> DecodeResult val where val implements Decoding, fmt implements DecoderFormatting
|
||||
from_bytes_partial = \bytes, fmt -> decode_with(bytes, decoder, fmt)
|
||||
from_bytes_partial = |bytes, fmt| decode_with(bytes, decoder, fmt)
|
||||
|
||||
## Decode a `List U8` utf-8 bytes and return a [Result] with no leftover bytes
|
||||
## expected. If successful returns `Ok val`, however, if there are bytes
|
||||
|
@ -153,7 +153,7 @@ from_bytes_partial = \bytes, fmt -> decode_with(bytes, decoder, fmt)
|
|||
## actual == expected
|
||||
## ```
|
||||
from_bytes : List U8, fmt -> Result val [Leftover (List U8)]DecodeError where val implements Decoding, fmt implements DecoderFormatting
|
||||
from_bytes = \bytes, fmt ->
|
||||
from_bytes = |bytes, fmt|
|
||||
when from_bytes_partial(bytes, fmt) is
|
||||
{ result, rest } ->
|
||||
if List.is_empty(rest) then
|
||||
|
@ -165,4 +165,4 @@ from_bytes = \bytes, fmt ->
|
|||
|
||||
## Transform the `val` of a [DecodeResult]
|
||||
map_result : DecodeResult a, (a -> b) -> DecodeResult b
|
||||
map_result = \{ result, rest }, mapper -> { result: Result.map_ok(result, mapper), rest }
|
||||
map_result = |{ result, rest }, mapper| { result: Result.map_ok(result, mapper), rest }
|
||||
|
|
|
@ -112,14 +112,14 @@ Dict k v := {
|
|||
]
|
||||
|
||||
is_eq : Dict k v, Dict k v -> Bool where v implements Eq
|
||||
is_eq = \xs, ys ->
|
||||
is_eq = |xs, ys|
|
||||
if len(xs) != len(ys) then
|
||||
Bool.false
|
||||
else
|
||||
walk_until(
|
||||
xs,
|
||||
Bool.true,
|
||||
\_, k, x_val ->
|
||||
|_, k, x_val|
|
||||
when get(ys, k) is
|
||||
Ok(y_val) if y_val == x_val ->
|
||||
Continue(Bool.true)
|
||||
|
@ -129,12 +129,12 @@ is_eq = \xs, ys ->
|
|||
)
|
||||
|
||||
hash_dict : hasher, Dict k v -> hasher where v implements Hash, hasher implements Hasher
|
||||
hash_dict = \hasher, dict -> Hash.hash_unordered(hasher, to_list(dict), List.walk)
|
||||
hash_dict = |hasher, dict| Hash.hash_unordered(hasher, to_list(dict), List.walk)
|
||||
|
||||
to_inspector_dict : Dict k v -> Inspector f where k implements Inspect & Hash & Eq, v implements Inspect, f implements InspectFormatter
|
||||
to_inspector_dict = \dict ->
|
||||
to_inspector_dict = |dict|
|
||||
Inspect.custom(
|
||||
\fmt ->
|
||||
|fmt|
|
||||
Inspect.apply(Inspect.dict(dict, walk, Inspect.to_inspector, Inspect.to_inspector), fmt),
|
||||
)
|
||||
|
||||
|
@ -143,7 +143,7 @@ to_inspector_dict = \dict ->
|
|||
## empty_dict = Dict.empty({})
|
||||
## ```
|
||||
empty : {} -> Dict * *
|
||||
empty = \{} ->
|
||||
empty = |{}|
|
||||
@Dict(
|
||||
{
|
||||
buckets: [],
|
||||
|
@ -158,19 +158,19 @@ empty = \{} ->
|
|||
## may provide a performance optimization if you know how many entries will be
|
||||
## inserted.
|
||||
with_capacity : U64 -> Dict * *
|
||||
with_capacity = \requested ->
|
||||
with_capacity = |requested|
|
||||
empty({})
|
||||
|> reserve(requested)
|
||||
|
||||
## Enlarge the dictionary for at least capacity additional elements
|
||||
reserve : Dict k v, U64 -> Dict k v
|
||||
reserve = \@Dict({ buckets, data, max_bucket_capacity: original_max_bucket_capacity, max_load_factor, shifts }), requested ->
|
||||
reserve = |@Dict({ buckets, data, max_bucket_capacity: original_max_bucket_capacity, max_load_factor, shifts }), requested|
|
||||
current_size = List.len(data)
|
||||
requested_size = Num.add_wrap(current_size, requested)
|
||||
size = Num.min(requested_size, max_size)
|
||||
|
||||
requested_shifts = calc_shifts_for_size(size, max_load_factor)
|
||||
if List.is_empty(buckets) || requested_shifts > shifts then
|
||||
if List.is_empty(buckets) or requested_shifts > shifts then
|
||||
(buckets0, max_bucket_capacity) = alloc_buckets_from_shift(requested_shifts, max_load_factor)
|
||||
buckets1 = fill_buckets_from_data(buckets0, data, requested_shifts)
|
||||
@Dict(
|
||||
|
@ -189,7 +189,7 @@ reserve = \@Dict({ buckets, data, max_bucket_capacity: original_max_bucket_capac
|
|||
## This function will require regenerating the metadata if the size changes.
|
||||
## There will still be some overhead due to dictionary metadata always being a power of 2.
|
||||
release_excess_capacity : Dict k v -> Dict k v
|
||||
release_excess_capacity = \@Dict({ buckets, data, max_bucket_capacity: original_max_bucket_capacity, max_load_factor, shifts }) ->
|
||||
release_excess_capacity = |@Dict({ buckets, data, max_bucket_capacity: original_max_bucket_capacity, max_load_factor, shifts })|
|
||||
size = List.len(data)
|
||||
|
||||
# NOTE: If we want, we technically could increase the load factor here to potentially minimize size more.
|
||||
|
@ -218,7 +218,7 @@ release_excess_capacity = \@Dict({ buckets, data, max_bucket_capacity: original_
|
|||
## capacity_of_dict = Dict.capacity(food_dict)
|
||||
## ```
|
||||
capacity : Dict * * -> U64
|
||||
capacity = \@Dict({ max_bucket_capacity }) ->
|
||||
capacity = |@Dict({ max_bucket_capacity })|
|
||||
max_bucket_capacity
|
||||
|
||||
## Returns a dictionary containing the key and value provided as input.
|
||||
|
@ -228,7 +228,7 @@ capacity = \@Dict({ max_bucket_capacity }) ->
|
|||
## |> Bool.is_eq(Dict.empty({}) |> Dict.insert("A", "B"))
|
||||
## ```
|
||||
single : k, v -> Dict k v
|
||||
single = \k, v ->
|
||||
single = |k, v|
|
||||
insert(empty({}), k, v)
|
||||
|
||||
## Returns dictionary with the keys and values specified by the input [List].
|
||||
|
@ -247,8 +247,8 @@ single = \k, v ->
|
|||
## If the list has few duplicate keys, it would be faster to allocate a dictionary
|
||||
## with the same capacity of the list and walk it calling [Dict.insert]
|
||||
from_list : List (k, v) -> Dict k v
|
||||
from_list = \data ->
|
||||
List.walk(data, empty({}), \dict, (k, v) -> insert(dict, k, v))
|
||||
from_list = |data|
|
||||
List.walk(data, empty({}), |dict, (k, v)| insert(dict, k, v))
|
||||
|
||||
## Returns the number of values in the dictionary.
|
||||
## ```roc
|
||||
|
@ -261,7 +261,7 @@ from_list = \data ->
|
|||
## |> Bool.is_eq(3)
|
||||
## ```
|
||||
len : Dict * * -> U64
|
||||
len = \@Dict({ data }) ->
|
||||
len = |@Dict({ data })|
|
||||
List.len(data)
|
||||
|
||||
## Check if the dictionary is empty.
|
||||
|
@ -271,7 +271,7 @@ len = \@Dict({ data }) ->
|
|||
## Dict.is_empty(Dict.empty({}))
|
||||
## ```
|
||||
is_empty : Dict * * -> Bool
|
||||
is_empty = \@Dict({ data }) ->
|
||||
is_empty = |@Dict({ data })|
|
||||
List.is_empty(data)
|
||||
|
||||
## Clears all elements from a dictionary keeping around the allocation if it isn't huge.
|
||||
|
@ -287,10 +287,10 @@ is_empty = \@Dict({ data }) ->
|
|||
## expect Dict.len(clear_songs) == 0
|
||||
## ```
|
||||
clear : Dict k v -> Dict k v
|
||||
clear = \@Dict({ buckets, data, max_bucket_capacity, max_load_factor, shifts }) ->
|
||||
clear = |@Dict({ buckets, data, max_bucket_capacity, max_load_factor, shifts })|
|
||||
@Dict(
|
||||
{
|
||||
buckets: List.map(buckets, \_ -> empty_bucket),
|
||||
buckets: List.map(buckets, |_| empty_bucket),
|
||||
# use take_first to keep around the capacity
|
||||
data: List.take_first(data, 0),
|
||||
max_bucket_capacity,
|
||||
|
@ -303,13 +303,13 @@ clear = \@Dict({ buckets, data, max_bucket_capacity, max_load_factor, shifts })
|
|||
## function on each of them which receives both the key and the old value. Then return a
|
||||
## new dictionary containing the same keys and the converted values.
|
||||
map : Dict k a, (k, a -> b) -> Dict k b
|
||||
map = \dict, transform ->
|
||||
map = |dict, transform|
|
||||
init = with_capacity(capacity(dict))
|
||||
|
||||
walk(
|
||||
dict,
|
||||
init,
|
||||
\answer, k, v ->
|
||||
|answer, k, v|
|
||||
insert(answer, k, transform(k, v)),
|
||||
)
|
||||
|
||||
|
@ -319,13 +319,13 @@ map = \dict, transform ->
|
|||
##
|
||||
## You may know a similar function named `concat_map` in other languages.
|
||||
join_map : Dict a b, (a, b -> Dict x y) -> Dict x y
|
||||
join_map = \dict, transform ->
|
||||
join_map = |dict, transform|
|
||||
init = with_capacity(capacity(dict)) # Might be a pessimization
|
||||
|
||||
walk(
|
||||
dict,
|
||||
init,
|
||||
\answer, k, v ->
|
||||
|answer, k, v|
|
||||
insert_all(answer, transform(k, v)),
|
||||
)
|
||||
|
||||
|
@ -341,8 +341,8 @@ join_map = \dict, transform ->
|
|||
## |> Bool.is_eq(36)
|
||||
## ```
|
||||
walk : Dict k v, state, (state, k, v -> state) -> state
|
||||
walk = \@Dict({ data }), initial_state, transform ->
|
||||
List.walk(data, initial_state, \state, (k, v) -> transform(state, k, v))
|
||||
walk = |@Dict({ data }), initial_state, transform|
|
||||
List.walk(data, initial_state, |state, (k, v)| transform(state, k, v))
|
||||
|
||||
## Same as [Dict.walk], except you can stop walking early.
|
||||
##
|
||||
|
@ -373,8 +373,8 @@ walk = \@Dict({ data }), initial_state, transform ->
|
|||
## expect someone_is_an_adult == Bool.true
|
||||
## ```
|
||||
walk_until : Dict k v, state, (state, k, v -> [Continue state, Break state]) -> state
|
||||
walk_until = \@Dict({ data }), initial_state, transform ->
|
||||
List.walk_until(data, initial_state, \state, (k, v) -> transform(state, k, v))
|
||||
walk_until = |@Dict({ data }), initial_state, transform|
|
||||
List.walk_until(data, initial_state, |state, (k, v)| transform(state, k, v))
|
||||
|
||||
## Run the given function on each key-value pair of a dictionary, and return
|
||||
## a dictionary with just the pairs for which the function returned `Bool.true`.
|
||||
|
@ -388,11 +388,11 @@ walk_until = \@Dict({ data }), initial_state, transform ->
|
|||
## |> Bool.is_eq(2)
|
||||
## ```
|
||||
keep_if : Dict k v, ((k, v) -> Bool) -> Dict k v
|
||||
keep_if = \dict, predicate ->
|
||||
keep_if = |dict, predicate|
|
||||
keep_if_help(dict, predicate, 0, Dict.len(dict))
|
||||
|
||||
keep_if_help : Dict k v, ((k, v) -> Bool), U64, U64 -> Dict k v
|
||||
keep_if_help = \@Dict(dict), predicate, index, length ->
|
||||
keep_if_help = |@Dict(dict), predicate, index, length|
|
||||
if index < length then
|
||||
(key, value) = list_get_unsafe(dict.data, index)
|
||||
if predicate((key, value)) then
|
||||
|
@ -414,8 +414,8 @@ keep_if_help = \@Dict(dict), predicate, index, length ->
|
|||
## |> Bool.is_eq(1)
|
||||
## ```
|
||||
drop_if : Dict k v, ((k, v) -> Bool) -> Dict k v
|
||||
drop_if = \dict, predicate ->
|
||||
Dict.keep_if(dict, \e -> Bool.not(predicate(e)))
|
||||
drop_if = |dict, predicate|
|
||||
Dict.keep_if(dict, |e| Bool.not(predicate(e)))
|
||||
|
||||
## Get the value for a given key. If there is a value for the specified key it
|
||||
## will return [Ok value], otherwise return [Err KeyNotFound].
|
||||
|
@ -429,7 +429,7 @@ drop_if = \dict, predicate ->
|
|||
## expect Dict.get(dictionary, 2000) == Err(KeyNotFound)
|
||||
## ```
|
||||
get : Dict k v, k -> Result v [KeyNotFound]
|
||||
get = \dict, key ->
|
||||
get = |dict, key|
|
||||
find(dict, key)
|
||||
|> .result
|
||||
|
||||
|
@ -442,7 +442,7 @@ get = \dict, key ->
|
|||
## |> Bool.is_eq(Bool.true)
|
||||
## ```
|
||||
contains : Dict k v, k -> Bool
|
||||
contains = \dict, key ->
|
||||
contains = |dict, key|
|
||||
find(dict, key)
|
||||
|> .result
|
||||
|> Result.is_ok
|
||||
|
@ -456,7 +456,7 @@ contains = \dict, key ->
|
|||
## |> Bool.is_eq(Ok(12))
|
||||
## ```
|
||||
insert : Dict k v, k, v -> Dict k v
|
||||
insert = \dict, key, value ->
|
||||
insert = |dict, key, value|
|
||||
@Dict({ buckets, data, max_bucket_capacity, max_load_factor, shifts }) =
|
||||
if len(dict) < capacity(dict) then
|
||||
dict
|
||||
|
@ -471,7 +471,7 @@ insert = \dict, key, value ->
|
|||
insert_helper(buckets, data, bucket_index, dist_and_fingerprint, key, value, max_bucket_capacity, max_load_factor, shifts)
|
||||
|
||||
insert_helper : List Bucket, List (k, v), U64, U32, k, v, U64, F32, U8 -> Dict k v
|
||||
insert_helper = \buckets0, data0, bucket_index0, dist_and_fingerprint0, key, value, max_bucket_capacity, max_load_factor, shifts ->
|
||||
insert_helper = |buckets0, data0, bucket_index0, dist_and_fingerprint0, key, value, max_bucket_capacity, max_load_factor, shifts|
|
||||
loaded = list_get_unsafe(buckets0, bucket_index0)
|
||||
if dist_and_fingerprint0 == loaded.dist_and_fingerprint then
|
||||
(found_key, _) = list_get_unsafe(data0, Num.to_u64(loaded.data_index))
|
||||
|
@ -502,7 +502,7 @@ insert_helper = \buckets0, data0, bucket_index0, dist_and_fingerprint0, key, val
|
|||
## |> Bool.is_eq(0)
|
||||
## ```
|
||||
remove : Dict k v, k -> Dict k v
|
||||
remove = \@Dict({ buckets, data, max_bucket_capacity, max_load_factor, shifts }), key ->
|
||||
remove = |@Dict({ buckets, data, max_bucket_capacity, max_load_factor, shifts }), key|
|
||||
if !(List.is_empty(data)) then
|
||||
(bucket_index0, dist_and_fingerprint0) = next_while_less(buckets, key, shifts)
|
||||
(bucket_index1, dist_and_fingerprint1) = remove_helper(buckets, bucket_index0, dist_and_fingerprint0, data, key)
|
||||
|
@ -516,7 +516,7 @@ remove = \@Dict({ buckets, data, max_bucket_capacity, max_load_factor, shifts })
|
|||
@Dict({ buckets, data, max_bucket_capacity, max_load_factor, shifts })
|
||||
|
||||
remove_helper : List Bucket, U64, U32, List (k, *), k -> (U64, U32) where k implements Eq
|
||||
remove_helper = \buckets, bucket_index, dist_and_fingerprint, data, key ->
|
||||
remove_helper = |buckets, bucket_index, dist_and_fingerprint, data, key|
|
||||
bucket = list_get_unsafe(buckets, bucket_index)
|
||||
if dist_and_fingerprint == bucket.dist_and_fingerprint then
|
||||
(found_key, _) = list_get_unsafe(data, Num.to_u64(bucket.data_index))
|
||||
|
@ -543,7 +543,7 @@ remove_helper = \buckets, bucket_index, dist_and_fingerprint, data, key ->
|
|||
## expect Dict.update(Dict.single("a", Bool.true), "a", alter_value) == Dict.empty({})
|
||||
## ```
|
||||
update : Dict k v, k, (Result v [Missing] -> Result v [Missing]) -> Dict k v
|
||||
update = \@Dict({ buckets, data, max_bucket_capacity, max_load_factor, shifts }), key, alter ->
|
||||
update = |@Dict({ buckets, data, max_bucket_capacity, max_load_factor, shifts }), key, alter|
|
||||
{ bucket_index, result } = find(@Dict({ buckets, data, max_bucket_capacity, max_load_factor, shifts }), key)
|
||||
when result is
|
||||
Ok(value) ->
|
||||
|
@ -582,7 +582,7 @@ update = \@Dict({ buckets, data, max_bucket_capacity, max_load_factor, shifts })
|
|||
Err(Missing) ->
|
||||
@Dict({ buckets, data, max_bucket_capacity, max_load_factor, shifts })
|
||||
|
||||
circular_dist = \start, end, size ->
|
||||
circular_dist = |start, end, size|
|
||||
correction =
|
||||
if start > end then
|
||||
size
|
||||
|
@ -604,7 +604,7 @@ circular_dist = \start, end, size ->
|
|||
## |> Bool.is_eq([(1, "One"), (2, "Two"), (3, "Three"), (4, "Four")])
|
||||
## ```
|
||||
to_list : Dict k v -> List (k, v)
|
||||
to_list = \@Dict({ data }) ->
|
||||
to_list = |@Dict({ data })|
|
||||
data
|
||||
|
||||
## Returns the keys of a dictionary as a [List].
|
||||
|
@ -619,8 +619,8 @@ to_list = \@Dict({ data }) ->
|
|||
## |> Bool.is_eq([1,2,3,4])
|
||||
## ```
|
||||
keys : Dict k v -> List k
|
||||
keys = \@Dict({ data }) ->
|
||||
List.map(data, \(k, _) -> k)
|
||||
keys = |@Dict({ data })|
|
||||
List.map(data, |(k, _)| k)
|
||||
|
||||
## Returns the values of a dictionary as a [List].
|
||||
## This requires allocating a temporary [List], prefer using [Dict.to_list] or [Dict.walk] instead.
|
||||
|
@ -634,8 +634,8 @@ keys = \@Dict({ data }) ->
|
|||
## |> Bool.is_eq(["One","Two","Three","Four"])
|
||||
## ```
|
||||
values : Dict k v -> List v
|
||||
values = \@Dict({ data }) ->
|
||||
List.map(data, \(_, v) -> v)
|
||||
values = |@Dict({ data })|
|
||||
List.map(data, |(_, v)| v)
|
||||
|
||||
## Combine two dictionaries by keeping the [union](https://en.wikipedia.org/wiki/Union_(set_theory))
|
||||
## of all the key-value pairs. This means that all the key-value pairs in
|
||||
|
@ -662,7 +662,7 @@ values = \@Dict({ data }) ->
|
|||
## Dict.insert_all(first, second) == expected
|
||||
## ```
|
||||
insert_all : Dict k v, Dict k v -> Dict k v
|
||||
insert_all = \xs, ys ->
|
||||
insert_all = |xs, ys|
|
||||
if len(ys) > len(xs) then
|
||||
insert_all(ys, xs)
|
||||
else
|
||||
|
@ -690,7 +690,7 @@ insert_all = \xs, ys ->
|
|||
## expect Dict.keep_shared(first, second) == expected
|
||||
## ```
|
||||
keep_shared : Dict k v, Dict k v -> Dict k v where v implements Eq
|
||||
keep_shared = \xs0, ys0 ->
|
||||
keep_shared = |xs0, ys0|
|
||||
(xs1, ys1) =
|
||||
if len(ys0) < len(xs0) then
|
||||
(ys0, xs0)
|
||||
|
@ -700,7 +700,7 @@ keep_shared = \xs0, ys0 ->
|
|||
walk(
|
||||
xs1,
|
||||
with_capacity(len(xs1)),
|
||||
\state, k, v ->
|
||||
|state, k, v|
|
||||
when get(ys1, k) is
|
||||
Ok(yv) if v == yv ->
|
||||
insert(state, k, v)
|
||||
|
@ -730,8 +730,8 @@ keep_shared = \xs0, ys0 ->
|
|||
## expect Dict.remove_all(first, second) == expected
|
||||
## ```
|
||||
remove_all : Dict k v, Dict k v -> Dict k v
|
||||
remove_all = \xs, ys ->
|
||||
walk(ys, xs, \state, k, _ -> remove(state, k))
|
||||
remove_all = |xs, ys|
|
||||
walk(ys, xs, |state, k, _| remove(state, k))
|
||||
|
||||
# Below here is a list of generic helpers and internal data types for Dict
|
||||
Bucket : {
|
||||
|
@ -747,17 +747,17 @@ initial_shifts = Num.sub_wrap(64, 3) # 2^(64-shifts) number of buckets
|
|||
max_size = Num.shift_left_by(1u64, 32)
|
||||
max_bucket_count = max_size
|
||||
|
||||
increment_dist = \dist_and_fingerprint ->
|
||||
increment_dist = |dist_and_fingerprint|
|
||||
Num.add_wrap(dist_and_fingerprint, dist_inc)
|
||||
|
||||
increment_dist_n = \dist_and_fingerprint, n ->
|
||||
increment_dist_n = |dist_and_fingerprint, n|
|
||||
Num.add_wrap(dist_and_fingerprint, Num.mul_wrap(n, dist_inc))
|
||||
|
||||
decrement_dist = \dist_and_fingerprint ->
|
||||
decrement_dist = |dist_and_fingerprint|
|
||||
Num.sub_wrap(dist_and_fingerprint, dist_inc)
|
||||
|
||||
find : Dict k v, k -> { bucket_index : U64, result : Result v [KeyNotFound] }
|
||||
find = \@Dict({ buckets, data, shifts }), key ->
|
||||
find = |@Dict({ buckets, data, shifts }), key|
|
||||
hash = hash_key(key)
|
||||
dist_and_fingerprint = dist_and_fingerprint_from_hash(hash)
|
||||
bucket_index = bucket_index_from_hash(hash, shifts)
|
||||
|
@ -772,7 +772,7 @@ find = \@Dict({ buckets, data, shifts }), key ->
|
|||
find_manual_unrolls = 2
|
||||
|
||||
find_first_unroll : List Bucket, U64, U32, List (k, v), k -> { bucket_index : U64, result : Result v [KeyNotFound] } where k implements Eq
|
||||
find_first_unroll = \buckets, bucket_index, dist_and_fingerprint, data, key ->
|
||||
find_first_unroll = |buckets, bucket_index, dist_and_fingerprint, data, key|
|
||||
# TODO: once we have short circuit evaluation, use it here and other similar locations in this file.
|
||||
# Avoid the nested if with else block inconvenience.
|
||||
bucket = list_get_unsafe(buckets, bucket_index)
|
||||
|
@ -786,7 +786,7 @@ find_first_unroll = \buckets, bucket_index, dist_and_fingerprint, data, key ->
|
|||
find_second_unroll(buckets, next_bucket_index(bucket_index, List.len(buckets)), increment_dist(dist_and_fingerprint), data, key)
|
||||
|
||||
find_second_unroll : List Bucket, U64, U32, List (k, v), k -> { bucket_index : U64, result : Result v [KeyNotFound] } where k implements Eq
|
||||
find_second_unroll = \buckets, bucket_index, dist_and_fingerprint, data, key ->
|
||||
find_second_unroll = |buckets, bucket_index, dist_and_fingerprint, data, key|
|
||||
bucket = list_get_unsafe(buckets, bucket_index)
|
||||
if dist_and_fingerprint == bucket.dist_and_fingerprint then
|
||||
(found_key, value) = list_get_unsafe(data, Num.to_u64(bucket.data_index))
|
||||
|
@ -798,7 +798,7 @@ find_second_unroll = \buckets, bucket_index, dist_and_fingerprint, data, key ->
|
|||
find_helper(buckets, next_bucket_index(bucket_index, List.len(buckets)), increment_dist(dist_and_fingerprint), data, key)
|
||||
|
||||
find_helper : List Bucket, U64, U32, List (k, v), k -> { bucket_index : U64, result : Result v [KeyNotFound] } where k implements Eq
|
||||
find_helper = \buckets, bucket_index, dist_and_fingerprint, data, key ->
|
||||
find_helper = |buckets, bucket_index, dist_and_fingerprint, data, key|
|
||||
bucket = list_get_unsafe(buckets, bucket_index)
|
||||
if dist_and_fingerprint == bucket.dist_and_fingerprint then
|
||||
(found_key, value) = list_get_unsafe(data, Num.to_u64(bucket.data_index))
|
||||
|
@ -812,7 +812,7 @@ find_helper = \buckets, bucket_index, dist_and_fingerprint, data, key ->
|
|||
find_helper(buckets, next_bucket_index(bucket_index, List.len(buckets)), increment_dist(dist_and_fingerprint), data, key)
|
||||
|
||||
remove_bucket : Dict k v, U64 -> Dict k v
|
||||
remove_bucket = \@Dict({ buckets: buckets0, data: data0, max_bucket_capacity, max_load_factor, shifts }), bucket_index0 ->
|
||||
remove_bucket = |@Dict({ buckets: buckets0, data: data0, max_bucket_capacity, max_load_factor, shifts }), bucket_index0|
|
||||
data_index_to_remove = list_get_unsafe(buckets0, bucket_index0) |> .data_index
|
||||
data_index_to_remove_u64 = Num.to_u64(data_index_to_remove)
|
||||
|
||||
|
@ -853,7 +853,7 @@ remove_bucket = \@Dict({ buckets: buckets0, data: data0, max_bucket_capacity, ma
|
|||
)
|
||||
|
||||
scan_for_index : List Bucket, U64, U32 -> U64
|
||||
scan_for_index = \buckets, bucket_index, data_index ->
|
||||
scan_for_index = |buckets, bucket_index, data_index|
|
||||
bucket = list_get_unsafe(buckets, bucket_index)
|
||||
if bucket.data_index != data_index then
|
||||
scan_for_index(buckets, next_bucket_index(bucket_index, List.len(buckets)), data_index)
|
||||
|
@ -861,7 +861,7 @@ scan_for_index = \buckets, bucket_index, data_index ->
|
|||
bucket_index
|
||||
|
||||
remove_bucket_helper : List Bucket, U64 -> (List Bucket, U64)
|
||||
remove_bucket_helper = \buckets, bucket_index ->
|
||||
remove_bucket_helper = |buckets, bucket_index|
|
||||
next_index = next_bucket_index(bucket_index, List.len(buckets))
|
||||
next_bucket = list_get_unsafe(buckets, next_index)
|
||||
# shift down until either empty or an element with correct spot is found
|
||||
|
@ -872,7 +872,7 @@ remove_bucket_helper = \buckets, bucket_index ->
|
|||
(buckets, bucket_index)
|
||||
|
||||
increase_size : Dict k v -> Dict k v
|
||||
increase_size = \@Dict({ data, max_bucket_capacity, max_load_factor, shifts }) ->
|
||||
increase_size = |@Dict({ data, max_bucket_capacity, max_load_factor, shifts })|
|
||||
if max_bucket_capacity != max_bucket_count then
|
||||
new_shifts = shifts |> Num.sub_wrap(1)
|
||||
(buckets0, new_max_bucket_capacity) = alloc_buckets_from_shift(new_shifts, max_load_factor)
|
||||
|
@ -890,7 +890,7 @@ increase_size = \@Dict({ data, max_bucket_capacity, max_load_factor, shifts }) -
|
|||
crash("Dict hit limit of ${Num.to_str(max_bucket_count)} elements. Unable to grow more.")
|
||||
|
||||
alloc_buckets_from_shift : U8, F32 -> (List Bucket, U64)
|
||||
alloc_buckets_from_shift = \shifts, max_load_factor ->
|
||||
alloc_buckets_from_shift = |shifts, max_load_factor|
|
||||
bucket_count = calc_num_buckets(shifts)
|
||||
if bucket_count == max_bucket_count then
|
||||
# reached the maximum, make sure we can use each bucket
|
||||
|
@ -905,49 +905,49 @@ alloc_buckets_from_shift = \shifts, max_load_factor ->
|
|||
(List.repeat(empty_bucket, bucket_count), max_bucket_capacity)
|
||||
|
||||
calc_shifts_for_size : U64, F32 -> U8
|
||||
calc_shifts_for_size = \size, max_load_factor ->
|
||||
calc_shifts_for_size = |size, max_load_factor|
|
||||
calc_shifts_for_size_helper(initial_shifts, size, max_load_factor)
|
||||
|
||||
calc_shifts_for_size_helper = \shifts, size, max_load_factor ->
|
||||
calc_shifts_for_size_helper = |shifts, size, max_load_factor|
|
||||
max_bucket_capacity =
|
||||
shifts
|
||||
|> calc_num_buckets
|
||||
|> Num.to_f32
|
||||
|> Num.mul(max_load_factor)
|
||||
|> Num.floor
|
||||
if shifts > 0 && max_bucket_capacity < size then
|
||||
if shifts > 0 and max_bucket_capacity < size then
|
||||
calc_shifts_for_size_helper(Num.sub_wrap(shifts, 1), size, max_load_factor)
|
||||
else
|
||||
shifts
|
||||
|
||||
calc_num_buckets = \shifts ->
|
||||
calc_num_buckets = |shifts|
|
||||
Num.min(Num.shift_left_by(1, Num.sub_wrap(64, shifts)), max_bucket_count)
|
||||
|
||||
fill_buckets_from_data = \buckets0, data, shifts ->
|
||||
fill_buckets_from_data = |buckets0, data, shifts|
|
||||
List.walk_with_index(
|
||||
data,
|
||||
buckets0,
|
||||
\buckets1, (key, _), data_index ->
|
||||
|buckets1, (key, _), data_index|
|
||||
(bucket_index, dist_and_fingerprint) = next_while_less(buckets1, key, shifts)
|
||||
place_and_shift_up(buckets1, { dist_and_fingerprint, data_index: Num.to_u32(data_index) }, bucket_index),
|
||||
)
|
||||
|
||||
next_while_less : List Bucket, k, U8 -> (U64, U32) where k implements Hash & Eq
|
||||
next_while_less = \buckets, key, shifts ->
|
||||
next_while_less = |buckets, key, shifts|
|
||||
hash = hash_key(key)
|
||||
dist_and_fingerprint = dist_and_fingerprint_from_hash(hash)
|
||||
bucket_index = bucket_index_from_hash(hash, shifts)
|
||||
|
||||
next_while_less_helper(buckets, bucket_index, dist_and_fingerprint)
|
||||
|
||||
next_while_less_helper = \buckets, bucket_index, dist_and_fingerprint ->
|
||||
next_while_less_helper = |buckets, bucket_index, dist_and_fingerprint|
|
||||
loaded = list_get_unsafe(buckets, bucket_index)
|
||||
if dist_and_fingerprint < loaded.dist_and_fingerprint then
|
||||
next_while_less_helper(buckets, next_bucket_index(bucket_index, List.len(buckets)), increment_dist(dist_and_fingerprint))
|
||||
else
|
||||
(bucket_index, dist_and_fingerprint)
|
||||
|
||||
place_and_shift_up = \buckets0, bucket, bucket_index ->
|
||||
place_and_shift_up = |buckets0, bucket, bucket_index|
|
||||
loaded = list_get_unsafe(buckets0, bucket_index)
|
||||
if loaded.dist_and_fingerprint != 0 then
|
||||
buckets1 = List.set(buckets0, bucket_index, bucket)
|
||||
|
@ -959,7 +959,7 @@ place_and_shift_up = \buckets0, bucket, bucket_index ->
|
|||
else
|
||||
List.set(buckets0, bucket_index, bucket)
|
||||
|
||||
next_bucket_index = \bucket_index, max_buckets ->
|
||||
next_bucket_index = |bucket_index, max_buckets|
|
||||
# I just ported this impl directly.
|
||||
# I am a bit confused why it is using an if over a mask.
|
||||
# Maybe compilers are smart enough to optimize this well.
|
||||
|
@ -969,20 +969,20 @@ next_bucket_index = \bucket_index, max_buckets ->
|
|||
else
|
||||
0
|
||||
|
||||
hash_key = \key ->
|
||||
hash_key = |key|
|
||||
create_low_level_hasher(PseudoRandSeed)
|
||||
|> Hash.hash(key)
|
||||
|> complete
|
||||
|
||||
dist_and_fingerprint_from_hash : U64 -> U32
|
||||
dist_and_fingerprint_from_hash = \hash ->
|
||||
dist_and_fingerprint_from_hash = |hash|
|
||||
hash
|
||||
|> Num.to_u32
|
||||
|> Num.bitwise_and(fingerprint_mask)
|
||||
|> Num.bitwise_or(dist_inc)
|
||||
|
||||
bucket_index_from_hash : U64, U8 -> U64
|
||||
bucket_index_from_hash = \hash, shifts ->
|
||||
bucket_index_from_hash = |hash, shifts|
|
||||
Num.shift_right_zf_by(hash, shifts)
|
||||
|
||||
expect
|
||||
|
@ -1087,7 +1087,7 @@ expect
|
|||
|> insert("bar", {})
|
||||
|> insert("baz", {})
|
||||
|
||||
contains(dict, "baz") && !(contains(dict, "other"))
|
||||
contains(dict, "baz") and !(contains(dict, "other"))
|
||||
|
||||
expect
|
||||
dict =
|
||||
|
@ -1145,17 +1145,17 @@ expect
|
|||
|> insert("l", 11)
|
||||
|
||||
(get(dict, "a") == Ok(0))
|
||||
&& (get(dict, "b") == Ok(1))
|
||||
&& (get(dict, "c") == Ok(2))
|
||||
&& (get(dict, "d") == Ok(3))
|
||||
&& (get(dict, "e") == Ok(4))
|
||||
&& (get(dict, "f") == Ok(5))
|
||||
&& (get(dict, "g") == Ok(6))
|
||||
&& (get(dict, "h") == Ok(7))
|
||||
&& (get(dict, "i") == Ok(8))
|
||||
&& (get(dict, "j") == Ok(9))
|
||||
&& (get(dict, "k") == Ok(10))
|
||||
&& (get(dict, "l") == Ok(11))
|
||||
and (get(dict, "b") == Ok(1))
|
||||
and (get(dict, "c") == Ok(2))
|
||||
and (get(dict, "d") == Ok(3))
|
||||
and (get(dict, "e") == Ok(4))
|
||||
and (get(dict, "f") == Ok(5))
|
||||
and (get(dict, "g") == Ok(6))
|
||||
and (get(dict, "h") == Ok(7))
|
||||
and (get(dict, "i") == Ok(8))
|
||||
and (get(dict, "j") == Ok(9))
|
||||
and (get(dict, "k") == Ok(10))
|
||||
and (get(dict, "l") == Ok(11))
|
||||
|
||||
# Force rehash.
|
||||
expect
|
||||
|
@ -1197,18 +1197,18 @@ expect
|
|||
|> insert("m", 12)
|
||||
|
||||
(get(dict, "a") == Ok(0))
|
||||
&& (get(dict, "b") == Ok(1))
|
||||
&& (get(dict, "c") == Ok(2))
|
||||
&& (get(dict, "d") == Ok(3))
|
||||
&& (get(dict, "e") == Ok(4))
|
||||
&& (get(dict, "f") == Ok(5))
|
||||
&& (get(dict, "g") == Ok(6))
|
||||
&& (get(dict, "h") == Ok(7))
|
||||
&& (get(dict, "i") == Ok(8))
|
||||
&& (get(dict, "j") == Ok(9))
|
||||
&& (get(dict, "k") == Ok(10))
|
||||
&& (get(dict, "l") == Ok(11))
|
||||
&& (get(dict, "m") == Ok(12))
|
||||
and (get(dict, "b") == Ok(1))
|
||||
and (get(dict, "c") == Ok(2))
|
||||
and (get(dict, "d") == Ok(3))
|
||||
and (get(dict, "e") == Ok(4))
|
||||
and (get(dict, "f") == Ok(5))
|
||||
and (get(dict, "g") == Ok(6))
|
||||
and (get(dict, "h") == Ok(7))
|
||||
and (get(dict, "i") == Ok(8))
|
||||
and (get(dict, "j") == Ok(9))
|
||||
and (get(dict, "k") == Ok(10))
|
||||
and (get(dict, "l") == Ok(11))
|
||||
and (get(dict, "m") == Ok(12))
|
||||
|
||||
expect
|
||||
empty({})
|
||||
|
@ -1227,7 +1227,7 @@ BadKey := U64 implements [
|
|||
]
|
||||
|
||||
hash_bad_key : hasher, BadKey -> hasher where hasher implements Hasher
|
||||
hash_bad_key = \hasher, _ -> Hash.hash(hasher, 0)
|
||||
hash_bad_key = |hasher, _| Hash.hash(hasher, 0)
|
||||
|
||||
expect
|
||||
bad_keys = [
|
||||
|
@ -1250,11 +1250,11 @@ expect
|
|||
List.walk(
|
||||
bad_keys,
|
||||
Dict.empty({}),
|
||||
\acc, k ->
|
||||
|acc, k|
|
||||
Dict.update(
|
||||
acc,
|
||||
k,
|
||||
\val ->
|
||||
|val|
|
||||
when val is
|
||||
Ok(p) -> Ok(Num.add_wrap(p, 1))
|
||||
Err(Missing) -> Ok(0),
|
||||
|
@ -1265,8 +1265,8 @@ expect
|
|||
List.walk(
|
||||
bad_keys,
|
||||
Bool.true,
|
||||
\acc, k ->
|
||||
acc && Dict.contains(dict, k),
|
||||
|acc, k|
|
||||
acc and Dict.contains(dict, k),
|
||||
)
|
||||
|
||||
all_inserted_correctly
|
||||
|
@ -1299,7 +1299,7 @@ LowLevelHasher := { initialized_seed : U64, state : U64 } implements [
|
|||
pseudo_seed : {} -> U64
|
||||
|
||||
create_low_level_hasher : [PseudoRandSeed, WithSeed U64] -> LowLevelHasher
|
||||
create_low_level_hasher = \seed_opt ->
|
||||
create_low_level_hasher = |seed_opt|
|
||||
seed =
|
||||
when seed_opt is
|
||||
PseudoRandSeed -> pseudo_seed({})
|
||||
|
@ -1307,7 +1307,7 @@ create_low_level_hasher = \seed_opt ->
|
|||
@LowLevelHasher({ initialized_seed: init_seed(seed), state: seed })
|
||||
|
||||
combine_state : LowLevelHasher, { a : U64, b : U64, seed : U64, length : U64 } -> LowLevelHasher
|
||||
combine_state = \@LowLevelHasher({ initialized_seed, state }), { a, b, seed, length } ->
|
||||
combine_state = |@LowLevelHasher({ initialized_seed, state }), { a, b, seed, length }|
|
||||
mum =
|
||||
a
|
||||
|> Num.bitwise_xor(wyp1)
|
||||
|
@ -1323,20 +1323,20 @@ combine_state = \@LowLevelHasher({ initialized_seed, state }), { a, b, seed, len
|
|||
|
||||
@LowLevelHasher({ initialized_seed, state: wymix(state, hash) })
|
||||
|
||||
init_seed = \seed ->
|
||||
init_seed = |seed|
|
||||
seed
|
||||
|> Num.bitwise_xor(wyp0)
|
||||
|> wymix(wyp1)
|
||||
|> Num.bitwise_xor(seed)
|
||||
|
||||
complete = \@LowLevelHasher({ state }) -> state
|
||||
complete = |@LowLevelHasher({ state })| state
|
||||
|
||||
# These implementations hash each value individually with the seed and then mix
|
||||
# the resulting hash with the state. There are other options that may be faster
|
||||
# like using the output of the last hash as the seed to the current hash.
|
||||
# I am simply not sure the tradeoffs here. Theoretically this method is more sound.
|
||||
# Either way, the performance will be similar and we can change this later.
|
||||
add_u8 = \@LowLevelHasher({ initialized_seed, state }), u8 ->
|
||||
add_u8 = |@LowLevelHasher({ initialized_seed, state }), u8|
|
||||
p0 = Num.to_u64(u8)
|
||||
a =
|
||||
Num.shift_left_by(p0, 16)
|
||||
|
@ -1346,7 +1346,7 @@ add_u8 = \@LowLevelHasher({ initialized_seed, state }), u8 ->
|
|||
|
||||
combine_state(@LowLevelHasher({ initialized_seed, state }), { a, b, seed: initialized_seed, length: 1 })
|
||||
|
||||
add_u16 = \@LowLevelHasher({ initialized_seed, state }), u16 ->
|
||||
add_u16 = |@LowLevelHasher({ initialized_seed, state }), u16|
|
||||
p0 = Num.bitwise_and(u16, 0xFF) |> Num.to_u64
|
||||
p1 = Num.shift_right_zf_by(u16, 8) |> Num.to_u64
|
||||
a =
|
||||
|
@ -1357,13 +1357,13 @@ add_u16 = \@LowLevelHasher({ initialized_seed, state }), u16 ->
|
|||
|
||||
combine_state(@LowLevelHasher({ initialized_seed, state }), { a, b, seed: initialized_seed, length: 2 })
|
||||
|
||||
add_u32 = \@LowLevelHasher({ initialized_seed, state }), u32 ->
|
||||
add_u32 = |@LowLevelHasher({ initialized_seed, state }), u32|
|
||||
p0 = Num.to_u64(u32)
|
||||
a = Num.shift_left_by(p0, 32) |> Num.bitwise_or(p0)
|
||||
|
||||
combine_state(@LowLevelHasher({ initialized_seed, state }), { a, b: a, seed: initialized_seed, length: 4 })
|
||||
|
||||
add_u64 = \@LowLevelHasher({ initialized_seed, state }), u64 ->
|
||||
add_u64 = |@LowLevelHasher({ initialized_seed, state }), u64|
|
||||
p0 = Num.bitwise_and(0xFFFF_FFFF, u64)
|
||||
p1 = Num.shift_right_zf_by(u64, 32)
|
||||
a = Num.shift_left_by(p0, 32) |> Num.bitwise_or(p1)
|
||||
|
@ -1371,7 +1371,7 @@ add_u64 = \@LowLevelHasher({ initialized_seed, state }), u64 ->
|
|||
|
||||
combine_state(@LowLevelHasher({ initialized_seed, state }), { a, b, seed: initialized_seed, length: 8 })
|
||||
|
||||
add_u128 = \@LowLevelHasher({ initialized_seed, state }), u128 ->
|
||||
add_u128 = |@LowLevelHasher({ initialized_seed, state }), u128|
|
||||
lower = u128 |> Num.to_u64
|
||||
upper = Num.shift_right_zf_by(u128, 64) |> Num.to_u64
|
||||
p0 = Num.bitwise_and(0xFFFF_FFFF, lower)
|
||||
|
@ -1384,7 +1384,7 @@ add_u128 = \@LowLevelHasher({ initialized_seed, state }), u128 ->
|
|||
combine_state(@LowLevelHasher({ initialized_seed, state }), { a, b, seed: initialized_seed, length: 16 })
|
||||
|
||||
add_bytes : LowLevelHasher, List U8 -> LowLevelHasher
|
||||
add_bytes = \@LowLevelHasher({ initialized_seed, state }), list ->
|
||||
add_bytes = |@LowLevelHasher({ initialized_seed, state }), list|
|
||||
length = List.len(list)
|
||||
abs =
|
||||
if length <= 16 then
|
||||
|
@ -1409,7 +1409,7 @@ add_bytes = \@LowLevelHasher({ initialized_seed, state }), list ->
|
|||
combine_state(@LowLevelHasher({ initialized_seed, state }), { a: abs.a, b: abs.b, seed: abs.seed, length })
|
||||
|
||||
hash_bytes_helper48 : U64, U64, U64, List U8, U64, U64 -> { a : U64, b : U64, seed : U64 }
|
||||
hash_bytes_helper48 = \seed, see1, see2, list, index, remaining ->
|
||||
hash_bytes_helper48 = |seed, see1, see2, list, index, remaining|
|
||||
new_seed = wymix(Num.bitwise_xor(wyr8(list, index), wyp1), Num.bitwise_xor(wyr8(list, Num.add_wrap(index, 8)), seed))
|
||||
new_see1 = wymix(Num.bitwise_xor(wyr8(list, Num.add_wrap(index, 16)), wyp2), Num.bitwise_xor(wyr8(list, Num.add_wrap(index, 24)), see1))
|
||||
new_see2 = wymix(Num.bitwise_xor(wyr8(list, Num.add_wrap(index, 32)), wyp3), Num.bitwise_xor(wyr8(list, Num.add_wrap(index, 40)), see2))
|
||||
|
@ -1428,7 +1428,7 @@ hash_bytes_helper48 = \seed, see1, see2, list, index, remaining ->
|
|||
{ a: wyr8(list, (Num.sub_wrap(new_remaining, 16) |> Num.add_wrap(new_index))), b: wyr8(list, (Num.sub_wrap(new_remaining, 8) |> Num.add_wrap(new_index))), seed: final_seed }
|
||||
|
||||
hash_bytes_helper16 : U64, List U8, U64, U64 -> { a : U64, b : U64, seed : U64 }
|
||||
hash_bytes_helper16 = \seed, list, index, remaining ->
|
||||
hash_bytes_helper16 = |seed, list, index, remaining|
|
||||
new_seed = wymix(Num.bitwise_xor(wyr8(list, index), wyp1), Num.bitwise_xor(wyr8(list, Num.add_wrap(index, 8)), seed))
|
||||
new_remaining = Num.sub_wrap(remaining, 16)
|
||||
new_index = Num.add_wrap(index, 16)
|
||||
|
@ -1448,13 +1448,13 @@ wyp3 : U64
|
|||
wyp3 = 0x589965cc75374cc3
|
||||
|
||||
wymix : U64, U64 -> U64
|
||||
wymix = \a, b ->
|
||||
wymix = |a, b|
|
||||
{ lower, upper } = wymum(a, b)
|
||||
|
||||
Num.bitwise_xor(lower, upper)
|
||||
|
||||
wymum : U64, U64 -> { lower : U64, upper : U64 }
|
||||
wymum = \a, b ->
|
||||
wymum = |a, b|
|
||||
r = Num.mul_wrap(Num.to_u128(a), Num.to_u128(b))
|
||||
lower = Num.to_u64(r)
|
||||
upper = Num.shift_right_zf_by(r, 64) |> Num.to_u64
|
||||
|
@ -1465,7 +1465,7 @@ wymum = \a, b ->
|
|||
|
||||
# Get the next 8 bytes as a U64
|
||||
wyr8 : List U8, U64 -> U64
|
||||
wyr8 = \list, index ->
|
||||
wyr8 = |list, index|
|
||||
# With seamless slices and Num.from_bytes, this should be possible to make faster and nicer.
|
||||
# It would also deal with the fact that on big endian systems we want to invert the order here.
|
||||
# Without seamless slices, we would need from_bytes to take an index.
|
||||
|
@ -1486,7 +1486,7 @@ wyr8 = \list, index ->
|
|||
|
||||
# Get the next 4 bytes as a U64 with some shifting.
|
||||
wyr4 : List U8, U64 -> U64
|
||||
wyr4 = \list, index ->
|
||||
wyr4 = |list, index|
|
||||
p1 = list_get_unsafe(list, index) |> Num.to_u64
|
||||
p2 = list_get_unsafe(list, Num.add_wrap(index, 1)) |> Num.to_u64
|
||||
p3 = list_get_unsafe(list, Num.add_wrap(index, 2)) |> Num.to_u64
|
||||
|
@ -1499,7 +1499,7 @@ wyr4 = \list, index ->
|
|||
# Get the next K bytes with some shifting.
|
||||
# K must be 3 or less.
|
||||
wyr3 : List U8, U64, U64 -> U64
|
||||
wyr3 = \list, index, k ->
|
||||
wyr3 = |list, index, k|
|
||||
# ((uint64_t)p[0])<<16)|(((uint64_t)p[k>>1])<<8)|p[k-1]
|
||||
p1 = list_get_unsafe(list, index) |> Num.to_u64
|
||||
p2 = list_get_unsafe(list, Num.shift_right_zf_by(k, 1) |> Num.add_wrap(index)) |> Num.to_u64
|
||||
|
@ -1704,7 +1704,7 @@ expect
|
|||
|> Dict.insert("Alice", 17)
|
||||
|> Dict.insert("Bob", 18)
|
||||
|> Dict.insert("Charlie", 19)
|
||||
|> Dict.walk_until(Bool.false, \_, _, age -> if age >= 18 then Break(Bool.true) else Continue(Bool.false))
|
||||
|> Dict.walk_until(Bool.false, |_, _, age| if age >= 18 then Break(Bool.true) else Continue(Bool.false))
|
||||
|> Bool.is_eq(Bool.true)
|
||||
|
||||
expect
|
||||
|
@ -1713,7 +1713,7 @@ expect
|
|||
|> Dict.insert("Alice", 17)
|
||||
|> Dict.insert("Bob", 18)
|
||||
|> Dict.insert("Charlie", 19)
|
||||
|> Dict.keep_if(\(_k, v) -> v >= 18)
|
||||
|> Dict.keep_if(|(_k, v)| v >= 18)
|
||||
|
||||
d2 =
|
||||
Dict.empty({})
|
||||
|
@ -1728,7 +1728,7 @@ expect
|
|||
|> Dict.insert("Alice", 17)
|
||||
|> Dict.insert("Bob", 18)
|
||||
|> Dict.insert("Charlie", 19)
|
||||
|> Dict.keep_if(\(k, _v) -> Str.ends_with(k, "e"))
|
||||
|> Dict.keep_if(|(k, _v)| Str.ends_with(k, "e"))
|
||||
|
||||
d2 =
|
||||
Dict.empty({})
|
||||
|
@ -1746,7 +1746,7 @@ expect
|
|||
|> Dict.insert(2, 2)
|
||||
|> Dict.insert(3, 3)
|
||||
|> Dict.insert(4, 4)
|
||||
|> Dict.keep_if(\(k, _v) -> !(List.contains(keys_to_delete, k)))
|
||||
|> Dict.keep_if(|(k, _v)| !(List.contains(keys_to_delete, k)))
|
||||
|
||||
d2 =
|
||||
Dict.empty({})
|
||||
|
@ -1765,7 +1765,7 @@ expect
|
|||
|> Dict.insert(2, 2)
|
||||
|> Dict.insert(3, 3)
|
||||
|> Dict.insert(4, 4)
|
||||
|> Dict.keep_if(\(k, _v) -> !(List.contains(keys_to_delete, k)))
|
||||
|> Dict.keep_if(|(k, _v)| !(List.contains(keys_to_delete, k)))
|
||||
|
||||
d2 =
|
||||
Dict.empty({})
|
||||
|
|
|
@ -84,10 +84,10 @@ EncoderFormatting implements
|
|||
## actual == expected
|
||||
## ```
|
||||
custom : (List U8, fmt -> List U8) -> Encoder fmt where fmt implements EncoderFormatting
|
||||
custom = \encoder -> @Encoder(encoder)
|
||||
custom = |encoder| @Encoder(encoder)
|
||||
|
||||
append_with : List U8, Encoder fmt, fmt -> List U8 where fmt implements EncoderFormatting
|
||||
append_with = \lst, @Encoder(do_encoding), fmt -> do_encoding(lst, fmt)
|
||||
append_with = |lst, @Encoder(do_encoding), fmt| do_encoding(lst, fmt)
|
||||
|
||||
## Appends the encoded representation of a value to an existing list of bytes.
|
||||
##
|
||||
|
@ -99,7 +99,7 @@ append_with = \lst, @Encoder(do_encoding), fmt -> do_encoding(lst, fmt)
|
|||
## actual == expected
|
||||
## ```
|
||||
append : List U8, val, fmt -> List U8 where val implements Encoding, fmt implements EncoderFormatting
|
||||
append = \lst, val, fmt -> append_with(lst, to_encoder(val), fmt)
|
||||
append = |lst, val, fmt| append_with(lst, to_encoder(val), fmt)
|
||||
|
||||
## Encodes a value to a list of bytes (`List U8`) according to the specified format.
|
||||
##
|
||||
|
@ -113,4 +113,4 @@ append = \lst, val, fmt -> append_with(lst, to_encoder(val), fmt)
|
|||
## actual == expected
|
||||
## ```
|
||||
to_bytes : val, fmt -> List U8 where val implements Encoding, fmt implements EncoderFormatting
|
||||
to_bytes = \val, fmt -> append_with([], to_encoder(val), fmt)
|
||||
to_bytes = |val, fmt| append_with([], to_encoder(val), fmt)
|
||||
|
|
|
@ -74,56 +74,56 @@ Hasher implements
|
|||
complete : a -> U64 where a implements Hasher
|
||||
|
||||
## Adds a string into a [Hasher] by hashing its UTF-8 bytes.
|
||||
hash_str_bytes = \hasher, s ->
|
||||
hash_str_bytes = |hasher, s|
|
||||
add_bytes(hasher, Str.to_utf8(s))
|
||||
|
||||
## Adds a list of [Hash]able elements to a [Hasher] by hashing each element.
|
||||
hash_list = \hasher, lst ->
|
||||
hash_list = |hasher, lst|
|
||||
List.walk(
|
||||
lst,
|
||||
hasher,
|
||||
\accum_hasher, elem ->
|
||||
|accum_hasher, elem|
|
||||
hash(accum_hasher, elem),
|
||||
)
|
||||
|
||||
## Adds a single [Bool] to a hasher.
|
||||
hash_bool : a, Bool -> a where a implements Hasher
|
||||
hash_bool = \hasher, b ->
|
||||
hash_bool = |hasher, b|
|
||||
as_u8 = if b then 1 else 0
|
||||
add_u8(hasher, as_u8)
|
||||
|
||||
## Adds a single I8 to a hasher.
|
||||
hash_i8 : a, I8 -> a where a implements Hasher
|
||||
hash_i8 = \hasher, n -> add_u8(hasher, Num.to_u8(n))
|
||||
hash_i8 = |hasher, n| add_u8(hasher, Num.to_u8(n))
|
||||
|
||||
## Adds a single I16 to a hasher.
|
||||
hash_i16 : a, I16 -> a where a implements Hasher
|
||||
hash_i16 = \hasher, n -> add_u16(hasher, Num.to_u16(n))
|
||||
hash_i16 = |hasher, n| add_u16(hasher, Num.to_u16(n))
|
||||
|
||||
## Adds a single I32 to a hasher.
|
||||
hash_i32 : a, I32 -> a where a implements Hasher
|
||||
hash_i32 = \hasher, n -> add_u32(hasher, Num.to_u32(n))
|
||||
hash_i32 = |hasher, n| add_u32(hasher, Num.to_u32(n))
|
||||
|
||||
## Adds a single I64 to a hasher.
|
||||
hash_i64 : a, I64 -> a where a implements Hasher
|
||||
hash_i64 = \hasher, n -> add_u64(hasher, Num.to_u64(n))
|
||||
hash_i64 = |hasher, n| add_u64(hasher, Num.to_u64(n))
|
||||
|
||||
## Adds a single I128 to a hasher.
|
||||
hash_i128 : a, I128 -> a where a implements Hasher
|
||||
hash_i128 = \hasher, n -> add_u128(hasher, Num.to_u128(n))
|
||||
hash_i128 = |hasher, n| add_u128(hasher, Num.to_u128(n))
|
||||
|
||||
## Adds a single [Dec] to a hasher.
|
||||
hash_dec : a, Dec -> a where a implements Hasher
|
||||
hash_dec = \hasher, n -> hash_i128(hasher, Num.without_decimal_point(n))
|
||||
hash_dec = |hasher, n| hash_i128(hasher, Num.without_decimal_point(n))
|
||||
|
||||
## Adds a container of [Hash]able elements to a [Hasher] by hashing each element.
|
||||
## The container is iterated using the walk method passed in.
|
||||
## The order of the elements does not affect the final hash.
|
||||
hash_unordered = \hasher, container, walk ->
|
||||
hash_unordered = |hasher, container, walk|
|
||||
walk(
|
||||
container,
|
||||
0,
|
||||
\accum, elem ->
|
||||
|accum, elem|
|
||||
x =
|
||||
# Note, we intentionally copy the hasher in every iteration.
|
||||
# Having the same base state is required for unordered hashing.
|
||||
|
@ -138,4 +138,4 @@ hash_unordered = \hasher, container, walk ->
|
|||
else
|
||||
next_accum,
|
||||
)
|
||||
|> \accum -> add_u64(hasher, accum)
|
||||
|> |accum| add_u64(hasher, accum)
|
||||
|
|
|
@ -81,21 +81,21 @@ InspectFormatter implements
|
|||
Inspector f := f -> f where f implements InspectFormatter
|
||||
|
||||
custom : (f -> f) -> Inspector f where f implements InspectFormatter
|
||||
custom = \fn -> @Inspector(fn)
|
||||
custom = |fn| @Inspector(fn)
|
||||
|
||||
apply : Inspector f, f -> f where f implements InspectFormatter
|
||||
apply = \@Inspector(fn), fmt -> fn(fmt)
|
||||
apply = |@Inspector(fn), fmt| fn(fmt)
|
||||
|
||||
Inspect implements
|
||||
to_inspector : val -> Inspector f where val implements Inspect, f implements InspectFormatter
|
||||
|
||||
inspect : val -> f where val implements Inspect, f implements InspectFormatter
|
||||
inspect = \val ->
|
||||
inspect = |val|
|
||||
@Inspector(val_fn) = to_inspector(val)
|
||||
val_fn(init({}))
|
||||
|
||||
to_str : val -> Str where val implements Inspect
|
||||
to_str = \val ->
|
||||
to_str = |val|
|
||||
val
|
||||
|> inspect
|
||||
|> to_dbg_str
|
||||
|
@ -134,16 +134,16 @@ DbgFormatter := { data : Str }
|
|||
]
|
||||
|
||||
dbg_init : {} -> DbgFormatter
|
||||
dbg_init = \{} -> @DbgFormatter({ data: "" })
|
||||
dbg_init = |{}| @DbgFormatter({ data: "" })
|
||||
|
||||
dbg_list : list, ElemWalker (DbgFormatter, Bool) list elem, (elem -> Inspector DbgFormatter) -> Inspector DbgFormatter
|
||||
dbg_list = \content, walk_fn, to_dbg_inspector ->
|
||||
custom_list_dbg = \f0 ->
|
||||
dbg_list = |content, walk_fn, to_dbg_inspector|
|
||||
custom_list_dbg = |f0|
|
||||
f1 = dbg_write(f0, "[")
|
||||
(f5, _) = walk_fn(
|
||||
content,
|
||||
(f1, Bool.false),
|
||||
\(f2, prepend_sep), elem ->
|
||||
|(f2, prepend_sep), elem|
|
||||
f3 =
|
||||
if prepend_sep then
|
||||
dbg_write(f2, ", ")
|
||||
|
@ -153,7 +153,7 @@ dbg_list = \content, walk_fn, to_dbg_inspector ->
|
|||
elem
|
||||
|> to_dbg_inspector
|
||||
|> apply(f3)
|
||||
|> \f4 -> (f4, Bool.true),
|
||||
|> |f4| (f4, Bool.true),
|
||||
)
|
||||
|
||||
dbg_write(f5, "]")
|
||||
|
@ -161,13 +161,13 @@ dbg_list = \content, walk_fn, to_dbg_inspector ->
|
|||
custom(custom_list_dbg)
|
||||
|
||||
dbg_set : set, ElemWalker (DbgFormatter, Bool) set elem, (elem -> Inspector DbgFormatter) -> Inspector DbgFormatter
|
||||
dbg_set = \content, walk_fn, to_dbg_inspector ->
|
||||
custom_dbg_set = \f0 ->
|
||||
dbg_set = |content, walk_fn, to_dbg_inspector|
|
||||
custom_dbg_set = |f0|
|
||||
f1 = dbg_write(f0, "{")
|
||||
(f5, _) = walk_fn(
|
||||
content,
|
||||
(f1, Bool.false),
|
||||
\(f2, prepend_sep), elem ->
|
||||
|(f2, prepend_sep), elem|
|
||||
f3 =
|
||||
if prepend_sep then
|
||||
dbg_write(f2, ", ")
|
||||
|
@ -177,7 +177,7 @@ dbg_set = \content, walk_fn, to_dbg_inspector ->
|
|||
elem
|
||||
|> to_dbg_inspector
|
||||
|> apply(f3)
|
||||
|> \f4 -> (f4, Bool.true),
|
||||
|> |f4| (f4, Bool.true),
|
||||
)
|
||||
|
||||
dbg_write(f5, "}")
|
||||
|
@ -185,13 +185,13 @@ dbg_set = \content, walk_fn, to_dbg_inspector ->
|
|||
custom(custom_dbg_set)
|
||||
|
||||
dbg_dict : dict, KeyValWalker (DbgFormatter, Bool) dict key value, (key -> Inspector DbgFormatter), (value -> Inspector DbgFormatter) -> Inspector DbgFormatter
|
||||
dbg_dict = \d, walk_fn, key_to_inspector, value_to_inspector ->
|
||||
custom_dbg_dict = \f0 ->
|
||||
dbg_dict = |d, walk_fn, key_to_inspector, value_to_inspector|
|
||||
custom_dbg_dict = |f0|
|
||||
f1 = dbg_write(f0, "{")
|
||||
(f5, _) = walk_fn(
|
||||
d,
|
||||
(f1, Bool.false),
|
||||
\(f2, prepend_sep), key, value ->
|
||||
|(f2, prepend_sep), key, value|
|
||||
f3 =
|
||||
if prepend_sep then
|
||||
dbg_write(f2, ", ")
|
||||
|
@ -200,8 +200,8 @@ dbg_dict = \d, walk_fn, key_to_inspector, value_to_inspector ->
|
|||
|
||||
apply(key_to_inspector(key), f3)
|
||||
|> dbg_write(": ")
|
||||
|> \x -> apply(value_to_inspector(value), x)
|
||||
|> \f4 -> (f4, Bool.true),
|
||||
|> |x| apply(value_to_inspector(value), x)
|
||||
|> |f4| (f4, Bool.true),
|
||||
)
|
||||
|
||||
dbg_write(f5, "}")
|
||||
|
@ -209,11 +209,11 @@ dbg_dict = \d, walk_fn, key_to_inspector, value_to_inspector ->
|
|||
custom(custom_dbg_dict)
|
||||
|
||||
dbg_tag : Str, List (Inspector DbgFormatter) -> Inspector DbgFormatter
|
||||
dbg_tag = \name, fields ->
|
||||
dbg_tag = |name, fields|
|
||||
if List.is_empty(fields) then
|
||||
custom(\f0 -> dbg_write(f0, name))
|
||||
custom(|f0| dbg_write(f0, name))
|
||||
else
|
||||
custom_dbg_tag = \f0 ->
|
||||
custom_dbg_tag = |f0|
|
||||
f1 =
|
||||
dbg_write(f0, "(")
|
||||
|> dbg_write(name)
|
||||
|
@ -221,9 +221,9 @@ dbg_tag = \name, fields ->
|
|||
f3 = List.walk(
|
||||
fields,
|
||||
f1,
|
||||
\f2, inspector ->
|
||||
|f2, inspector|
|
||||
dbg_write(f2, " ")
|
||||
|> \x -> apply(inspector, x),
|
||||
|> |x| apply(inspector, x),
|
||||
)
|
||||
|
||||
dbg_write(f3, ")")
|
||||
|
@ -231,13 +231,13 @@ dbg_tag = \name, fields ->
|
|||
custom(custom_dbg_tag)
|
||||
|
||||
dbg_tuple : List (Inspector DbgFormatter) -> Inspector DbgFormatter
|
||||
dbg_tuple = \fields ->
|
||||
custom_dbg_tuple = \f0 ->
|
||||
dbg_tuple = |fields|
|
||||
custom_dbg_tuple = |f0|
|
||||
f1 = dbg_write(f0, "(")
|
||||
(f5, _) = List.walk(
|
||||
fields,
|
||||
(f1, Bool.false),
|
||||
\(f2, prepend_sep), inspector ->
|
||||
|(f2, prepend_sep), inspector|
|
||||
f3 =
|
||||
if prepend_sep then
|
||||
dbg_write(f2, ", ")
|
||||
|
@ -245,7 +245,7 @@ dbg_tuple = \fields ->
|
|||
f2
|
||||
|
||||
apply(inspector, f3)
|
||||
|> \f4 -> (f4, Bool.true),
|
||||
|> |f4| (f4, Bool.true),
|
||||
)
|
||||
|
||||
dbg_write(f5, ")")
|
||||
|
@ -253,13 +253,13 @@ dbg_tuple = \fields ->
|
|||
custom(custom_dbg_tuple)
|
||||
|
||||
dbg_record : List { key : Str, value : Inspector DbgFormatter } -> Inspector DbgFormatter
|
||||
dbg_record = \fields ->
|
||||
custom_dbg_record = \f0 ->
|
||||
dbg_record = |fields|
|
||||
custom_dbg_record = |f0|
|
||||
f1 = dbg_write(f0, "{")
|
||||
(f5, _) = List.walk(
|
||||
fields,
|
||||
(f1, Bool.false),
|
||||
\(f2, prepend_sep), { key, value } ->
|
||||
|(f2, prepend_sep), { key, value }|
|
||||
f3 =
|
||||
if prepend_sep then
|
||||
dbg_write(f2, ", ")
|
||||
|
@ -268,8 +268,8 @@ dbg_record = \fields ->
|
|||
|
||||
dbg_write(f3, key)
|
||||
|> dbg_write(": ")
|
||||
|> \x -> apply(value, x)
|
||||
|> \f4 -> (f4, Bool.true),
|
||||
|> |x| apply(value, x)
|
||||
|> |f4| (f4, Bool.true),
|
||||
)
|
||||
|
||||
dbg_write(f5, "}")
|
||||
|
@ -277,12 +277,12 @@ dbg_record = \fields ->
|
|||
custom(custom_dbg_record)
|
||||
|
||||
dbg_bool : Bool -> Inspector DbgFormatter
|
||||
dbg_bool = \b ->
|
||||
dbg_bool = |b|
|
||||
text = if b then "Bool.true" else "Bool.false"
|
||||
custom(\f0 -> dbg_write(f0, text))
|
||||
custom(|f0| dbg_write(f0, text))
|
||||
|
||||
dbg_str : Str -> Inspector DbgFormatter
|
||||
dbg_str = \s ->
|
||||
dbg_str = |s|
|
||||
# escape invisible unicode characters as in fmt_str_body crates/compiler/fmt/src/expr.rs
|
||||
escape_s =
|
||||
Str.replace_each(s, "\u(feff)", "\\u(feff)")
|
||||
|
@ -290,7 +290,7 @@ dbg_str = \s ->
|
|||
|> Str.replace_each("\u(200c)", "\\u(200c)")
|
||||
|> Str.replace_each("\u(200d)", "\\u(200d)")
|
||||
|
||||
custom_dbg_str = \f0 ->
|
||||
custom_dbg_str = |f0|
|
||||
dbg_write(f0, "\"")
|
||||
|> dbg_write(escape_s)
|
||||
|> dbg_write("\"")
|
||||
|
@ -298,68 +298,68 @@ dbg_str = \s ->
|
|||
custom(custom_dbg_str)
|
||||
|
||||
dbg_opaque : * -> Inspector DbgFormatter
|
||||
dbg_opaque = \_ ->
|
||||
custom(\f0 -> dbg_write(f0, "<opaque>"))
|
||||
dbg_opaque = |_|
|
||||
custom(|f0| dbg_write(f0, "<opaque>"))
|
||||
|
||||
dbg_function : * -> Inspector DbgFormatter
|
||||
dbg_function = \_ ->
|
||||
custom(\f0 -> dbg_write(f0, "<function>"))
|
||||
dbg_function = |_|
|
||||
custom(|f0| dbg_write(f0, "<function>"))
|
||||
|
||||
dbg_u8 : U8 -> Inspector DbgFormatter
|
||||
dbg_u8 = \num ->
|
||||
custom(\f0 -> dbg_write(f0, Num.to_str(num)))
|
||||
dbg_u8 = |num|
|
||||
custom(|f0| dbg_write(f0, Num.to_str(num)))
|
||||
|
||||
dbg_i8 : I8 -> Inspector DbgFormatter
|
||||
dbg_i8 = \num ->
|
||||
custom(\f0 -> dbg_write(f0, Num.to_str(num)))
|
||||
dbg_i8 = |num|
|
||||
custom(|f0| dbg_write(f0, Num.to_str(num)))
|
||||
|
||||
dbg_u16 : U16 -> Inspector DbgFormatter
|
||||
dbg_u16 = \num ->
|
||||
custom(\f0 -> dbg_write(f0, Num.to_str(num)))
|
||||
dbg_u16 = |num|
|
||||
custom(|f0| dbg_write(f0, Num.to_str(num)))
|
||||
|
||||
dbg_i16 : I16 -> Inspector DbgFormatter
|
||||
dbg_i16 = \num ->
|
||||
custom(\f0 -> dbg_write(f0, Num.to_str(num)))
|
||||
dbg_i16 = |num|
|
||||
custom(|f0| dbg_write(f0, Num.to_str(num)))
|
||||
|
||||
dbg_u32 : U32 -> Inspector DbgFormatter
|
||||
dbg_u32 = \num ->
|
||||
custom(\f0 -> dbg_write(f0, Num.to_str(num)))
|
||||
dbg_u32 = |num|
|
||||
custom(|f0| dbg_write(f0, Num.to_str(num)))
|
||||
|
||||
dbg_i32 : I32 -> Inspector DbgFormatter
|
||||
dbg_i32 = \num ->
|
||||
custom(\f0 -> dbg_write(f0, Num.to_str(num)))
|
||||
dbg_i32 = |num|
|
||||
custom(|f0| dbg_write(f0, Num.to_str(num)))
|
||||
|
||||
dbg_u64 : U64 -> Inspector DbgFormatter
|
||||
dbg_u64 = \num ->
|
||||
custom(\f0 -> dbg_write(f0, Num.to_str(num)))
|
||||
dbg_u64 = |num|
|
||||
custom(|f0| dbg_write(f0, Num.to_str(num)))
|
||||
|
||||
dbg_i64 : I64 -> Inspector DbgFormatter
|
||||
dbg_i64 = \num ->
|
||||
custom(\f0 -> dbg_write(f0, Num.to_str(num)))
|
||||
dbg_i64 = |num|
|
||||
custom(|f0| dbg_write(f0, Num.to_str(num)))
|
||||
|
||||
dbg_u128 : U128 -> Inspector DbgFormatter
|
||||
dbg_u128 = \num ->
|
||||
custom(\f0 -> dbg_write(f0, Num.to_str(num)))
|
||||
dbg_u128 = |num|
|
||||
custom(|f0| dbg_write(f0, Num.to_str(num)))
|
||||
|
||||
dbg_i128 : I128 -> Inspector DbgFormatter
|
||||
dbg_i128 = \num ->
|
||||
custom(\f0 -> dbg_write(f0, Num.to_str(num)))
|
||||
dbg_i128 = |num|
|
||||
custom(|f0| dbg_write(f0, Num.to_str(num)))
|
||||
|
||||
dbg_f32 : F32 -> Inspector DbgFormatter
|
||||
dbg_f32 = \num ->
|
||||
custom(\f0 -> dbg_write(f0, Num.to_str(num)))
|
||||
dbg_f32 = |num|
|
||||
custom(|f0| dbg_write(f0, Num.to_str(num)))
|
||||
|
||||
dbg_f64 : F64 -> Inspector DbgFormatter
|
||||
dbg_f64 = \num ->
|
||||
custom(\f0 -> dbg_write(f0, Num.to_str(num)))
|
||||
dbg_f64 = |num|
|
||||
custom(|f0| dbg_write(f0, Num.to_str(num)))
|
||||
|
||||
dbg_dec : Dec -> Inspector DbgFormatter
|
||||
dbg_dec = \num ->
|
||||
custom(\f0 -> dbg_write(f0, Num.to_str(num)))
|
||||
dbg_dec = |num|
|
||||
custom(|f0| dbg_write(f0, Num.to_str(num)))
|
||||
|
||||
dbg_write : DbgFormatter, Str -> DbgFormatter
|
||||
dbg_write = \@DbgFormatter({ data }), added ->
|
||||
dbg_write = |@DbgFormatter({ data }), added|
|
||||
@DbgFormatter({ data: Str.concat(data, added) })
|
||||
|
||||
to_dbg_str : DbgFormatter -> Str
|
||||
to_dbg_str = \@DbgFormatter({ data }) -> data
|
||||
to_dbg_str = |@DbgFormatter({ data })| data
|
||||
|
|
|
@ -227,7 +227,7 @@ import Num exposing [U64, Num, U8]
|
|||
## List.is_empty([])
|
||||
## ```
|
||||
is_empty : List * -> Bool
|
||||
is_empty = \list ->
|
||||
is_empty = |list|
|
||||
List.len(list) == 0
|
||||
|
||||
# unsafe primitive that does not perform a bounds check
|
||||
|
@ -242,7 +242,7 @@ get_unsafe : List a, U64 -> a
|
|||
## expect List.get([100, 200, 300], 5) == Err(OutOfBounds)
|
||||
## ```
|
||||
get : List a, U64 -> Result a [OutOfBounds]
|
||||
get = \list, index ->
|
||||
get = |list, index|
|
||||
if index < List.len(list) then
|
||||
Ok(List.get_unsafe(list, index))
|
||||
else
|
||||
|
@ -253,7 +253,7 @@ get = \list, index ->
|
|||
replace_unsafe : List a, U64, a -> { list : List a, value : a }
|
||||
|
||||
replace : List a, U64, a -> { list : List a, value : a }
|
||||
replace = \list, index, new_value ->
|
||||
replace = |list, index, new_value|
|
||||
if index < List.len(list) then
|
||||
List.replace_unsafe(list, index, new_value)
|
||||
else
|
||||
|
@ -268,7 +268,7 @@ replace = \list, index, new_value ->
|
|||
##
|
||||
## To drop the element at a given index, instead of replacing it, see [List.drop_at].
|
||||
set : List a, U64, a -> List a
|
||||
set = \list, index, value ->
|
||||
set = |list, index, value|
|
||||
(List.replace(list, index, value)).list
|
||||
|
||||
## Updates the element at the given index with the given function.
|
||||
|
@ -281,7 +281,7 @@ set = \list, index, value ->
|
|||
## To replace the element at a given index, instead of updating based on the current value,
|
||||
## see [List.set] and [List.replace]
|
||||
update : List a, U64, (a -> a) -> List a
|
||||
update = \list, index, func ->
|
||||
update = |list, index, func|
|
||||
when List.get(list, index) is
|
||||
Err(OutOfBounds) -> list
|
||||
Ok(value) ->
|
||||
|
@ -292,7 +292,7 @@ update = \list, index, func ->
|
|||
expect
|
||||
list : List U64
|
||||
list = [1, 2, 3]
|
||||
got = update(list, 1, \x -> x + 42)
|
||||
got = update(list, 1, |x| x + 42)
|
||||
want = [1, 44, 3]
|
||||
got == want
|
||||
|
||||
|
@ -300,7 +300,7 @@ expect
|
|||
expect
|
||||
list : List U64
|
||||
list = [1, 2, 3]
|
||||
got = update(list, 5, \x -> x + 42)
|
||||
got = update(list, 5, |x| x + 42)
|
||||
got == list
|
||||
|
||||
# Update chain
|
||||
|
@ -309,9 +309,9 @@ expect
|
|||
list = [1, 2, 3]
|
||||
got =
|
||||
list
|
||||
|> update(0, \x -> x + 10)
|
||||
|> update(1, \x -> x + 20)
|
||||
|> update(2, \x -> x + 30)
|
||||
|> update(0, |x| x + 10)
|
||||
|> update(1, |x| x + 20)
|
||||
|> update(2, |x| x + 30)
|
||||
want = [11, 22, 33]
|
||||
got == want
|
||||
|
||||
|
@ -323,7 +323,7 @@ expect
|
|||
## |> List.append(3)
|
||||
## ```
|
||||
append : List a, a -> List a
|
||||
append = \list, element ->
|
||||
append = |list, element|
|
||||
list
|
||||
|> List.reserve(1)
|
||||
|> List.append_unsafe(element)
|
||||
|
@ -338,7 +338,7 @@ append = \list, element ->
|
|||
## |> List.append_if_ok(Err(3))
|
||||
## ```
|
||||
append_if_ok : List a, Result a * -> List a
|
||||
append_if_ok = \list, result ->
|
||||
append_if_ok = |list, result|
|
||||
when result is
|
||||
Ok(elem) -> append(list, elem)
|
||||
Err(_) -> list
|
||||
|
@ -369,7 +369,7 @@ prepend : List a, a -> List a
|
|||
## |> List.prepend(Err(1))
|
||||
## ```
|
||||
prepend_if_ok : List a, Result a * -> List a
|
||||
prepend_if_ok = \list, result ->
|
||||
prepend_if_ok = |list, result|
|
||||
when result is
|
||||
Ok(elem) -> prepend(list, elem)
|
||||
Err(_) -> list
|
||||
|
@ -405,7 +405,7 @@ concat : List a, List a -> List a
|
|||
## expect List.last([]) == Err(ListWasEmpty)
|
||||
## ```
|
||||
last : List a -> Result a [ListWasEmpty]
|
||||
last = \list ->
|
||||
last = |list|
|
||||
when List.get(list, Num.sub_saturated(List.len(list), 1)) is
|
||||
Ok(v) -> Ok(v)
|
||||
Err(_) -> Err(ListWasEmpty)
|
||||
|
@ -419,15 +419,15 @@ last = \list ->
|
|||
## |> List.single
|
||||
## ```
|
||||
single : a -> List a
|
||||
single = \x -> [x]
|
||||
single = |x| [x]
|
||||
|
||||
## Returns a list with the given length, where every element is the given value.
|
||||
repeat : a, U64 -> List a
|
||||
repeat = \value, count ->
|
||||
repeat = |value, count|
|
||||
repeat_help(value, count, List.with_capacity(count))
|
||||
|
||||
repeat_help : a, U64, List a -> List a
|
||||
repeat_help = \value, count, accum ->
|
||||
repeat_help = |value, count, accum|
|
||||
if count > 0 then
|
||||
repeat_help(value, Num.sub_wrap(count, 1), List.append_unsafe(accum, value))
|
||||
else
|
||||
|
@ -438,11 +438,11 @@ repeat_help = \value, count, accum ->
|
|||
## expect List.reverse([1, 2, 3]) == [3, 2, 1]
|
||||
## ```
|
||||
reverse : List a -> List a
|
||||
reverse = \list ->
|
||||
reverse = |list|
|
||||
end = List.len(list) |> Num.sub_saturated(1)
|
||||
reverse_help(List.clone(list), 0, end)
|
||||
|
||||
reverse_help = \list, left, right ->
|
||||
reverse_help = |list, left, right|
|
||||
if left < right then
|
||||
reverse_help(List.swap(list, left, right), Num.add_wrap(left, 1), Num.sub_wrap(right, 1))
|
||||
else
|
||||
|
@ -458,15 +458,15 @@ clone : List a -> List a
|
|||
## expect List.join([]) == []
|
||||
## ```
|
||||
join : List (List a) -> List a
|
||||
join = \lists ->
|
||||
join = |lists|
|
||||
total_length =
|
||||
List.walk(lists, 0, \state, list -> Num.add_wrap(state, List.len(list)))
|
||||
List.walk(lists, 0, |state, list| Num.add_wrap(state, List.len(list)))
|
||||
|
||||
List.walk(lists, List.with_capacity(total_length), \state, list -> List.concat(state, list))
|
||||
List.walk(lists, List.with_capacity(total_length), |state, list| List.concat(state, list))
|
||||
|
||||
contains : List a, a -> Bool where a implements Eq
|
||||
contains = \list, needle ->
|
||||
List.any(list, \x -> x == needle)
|
||||
contains = |list, needle|
|
||||
List.any(list, |x| x == needle)
|
||||
|
||||
## Build a value using each element in the list.
|
||||
##
|
||||
|
@ -501,12 +501,12 @@ contains = \list, needle ->
|
|||
## Note that in other languages, `walk` is sometimes called `reduce`,
|
||||
## `fold`, `fold_left`, or `foldl`.
|
||||
walk : List elem, state, (state, elem -> state) -> state
|
||||
walk = \list, init, func ->
|
||||
walk = |list, init, func|
|
||||
walk_help(list, init, func, 0, List.len(list))
|
||||
|
||||
## internal helper
|
||||
walk_help : List elem, s, (s, elem -> s), U64, U64 -> s
|
||||
walk_help = \list, state, f, index, length ->
|
||||
walk_help = |list, state, f, index, length|
|
||||
if index < length then
|
||||
next_state = f(state, List.get_unsafe(list, index))
|
||||
|
||||
|
@ -516,12 +516,12 @@ walk_help = \list, state, f, index, length ->
|
|||
|
||||
## Like [walk], but at each step the function also receives the index of the current element.
|
||||
walk_with_index : List elem, state, (state, elem, U64 -> state) -> state
|
||||
walk_with_index = \list, init, func ->
|
||||
walk_with_index = |list, init, func|
|
||||
walk_with_index_help(list, init, func, 0, List.len(list))
|
||||
|
||||
## internal helper
|
||||
walk_with_index_help : List elem, s, (s, elem, U64 -> s), U64, U64 -> s
|
||||
walk_with_index_help = \list, state, f, index, length ->
|
||||
walk_with_index_help = |list, state, f, index, length|
|
||||
if index < length then
|
||||
next_state = f(state, List.get_unsafe(list, index), index)
|
||||
|
||||
|
@ -531,14 +531,14 @@ walk_with_index_help = \list, state, f, index, length ->
|
|||
|
||||
## Like [walk_until], but at each step the function also receives the index of the current element.
|
||||
walk_with_index_until : List elem, state, (state, elem, U64 -> [Continue state, Break state]) -> state
|
||||
walk_with_index_until = \list, state, f ->
|
||||
walk_with_index_until = |list, state, f|
|
||||
when walk_with_index_until_help(list, state, f, 0, List.len(list)) is
|
||||
Continue(new) -> new
|
||||
Break(new) -> new
|
||||
|
||||
## internal helper
|
||||
walk_with_index_until_help : List elem, s, (s, elem, U64 -> [Continue s, Break b]), U64, U64 -> [Continue s, Break b]
|
||||
walk_with_index_until_help = \list, state, f, index, length ->
|
||||
walk_with_index_until_help = |list, state, f, index, length|
|
||||
if index < length then
|
||||
when f(state, List.get_unsafe(list, index), index) is
|
||||
Continue(next_state) ->
|
||||
|
@ -551,12 +551,12 @@ walk_with_index_until_help = \list, state, f, index, length ->
|
|||
## Note that in other languages, `walk_backwards` is sometimes called `reduce_right`,
|
||||
## `fold`, `fold_right`, or `foldr`.
|
||||
walk_backwards : List elem, state, (state, elem -> state) -> state
|
||||
walk_backwards = \list, state, func ->
|
||||
walk_backwards = |list, state, func|
|
||||
walk_backwards_help(list, state, func, len(list))
|
||||
|
||||
## internal helper
|
||||
walk_backwards_help : List elem, state, (state, elem -> state), U64 -> state
|
||||
walk_backwards_help = \list, state, f, index_plus_one ->
|
||||
walk_backwards_help = |list, state, f, index_plus_one|
|
||||
if index_plus_one == 0 then
|
||||
state
|
||||
else
|
||||
|
@ -577,47 +577,47 @@ walk_backwards_help = \list, state, f, index_plus_one ->
|
|||
## As such, it is typically better for performance to use this over [List.walk]
|
||||
## if returning `Break` earlier than the last element is expected to be common.
|
||||
walk_until : List elem, state, (state, elem -> [Continue state, Break state]) -> state
|
||||
walk_until = \list, initial, step ->
|
||||
walk_until = |list, initial, step|
|
||||
when List.iterate(list, initial, step) is
|
||||
Continue(new) -> new
|
||||
Break(new) -> new
|
||||
|
||||
## Same as [List.walk_until], but does it from the end of the list instead.
|
||||
walk_backwards_until : List elem, state, (state, elem -> [Continue state, Break state]) -> state
|
||||
walk_backwards_until = \list, initial, func ->
|
||||
walk_backwards_until = |list, initial, func|
|
||||
when List.iterate_backwards(list, initial, func) is
|
||||
Continue(new) -> new
|
||||
Break(new) -> new
|
||||
|
||||
## Walks to the end of the list from a specified starting index
|
||||
walk_from : List elem, U64, state, (state, elem -> state) -> state
|
||||
walk_from = \list, index, state, func ->
|
||||
walk_from = |list, index, state, func|
|
||||
step : _, _ -> [Continue _, Break []]
|
||||
step = \current_state, element -> Continue(func(current_state, element))
|
||||
step = |current_state, element| Continue(func(current_state, element))
|
||||
|
||||
when List.iter_help(list, state, step, index, List.len(list)) is
|
||||
Continue(new) -> new
|
||||
|
||||
## A combination of [List.walk_from] and [List.walk_until]
|
||||
walk_from_until : List elem, U64, state, (state, elem -> [Continue state, Break state]) -> state
|
||||
walk_from_until = \list, index, state, func ->
|
||||
walk_from_until = |list, index, state, func|
|
||||
when List.iter_help(list, state, func, index, List.len(list)) is
|
||||
Continue(new) -> new
|
||||
Break(new) -> new
|
||||
|
||||
sum : List (Num a) -> Num a
|
||||
sum = \list ->
|
||||
sum = |list|
|
||||
List.walk(list, 0, Num.add)
|
||||
|
||||
product : List (Num a) -> Num a
|
||||
product = \list ->
|
||||
product = |list|
|
||||
List.walk(list, 1, Num.mul)
|
||||
|
||||
## Run the given predicate on each element of the list, returning `Bool.true` if
|
||||
## any of the elements satisfy it.
|
||||
any : List a, (a -> Bool) -> Bool
|
||||
any = \list, predicate ->
|
||||
looper = \{}, element ->
|
||||
any = |list, predicate|
|
||||
looper = |{}, element|
|
||||
if predicate(element) then
|
||||
Break({})
|
||||
else
|
||||
|
@ -630,8 +630,8 @@ any = \list, predicate ->
|
|||
## Run the given predicate on each element of the list, returning `Bool.true` if
|
||||
## all of the elements satisfy it.
|
||||
all : List a, (a -> Bool) -> Bool
|
||||
all = \list, predicate ->
|
||||
looper = \{}, element ->
|
||||
all = |list, predicate|
|
||||
looper = |{}, element|
|
||||
if predicate(element) then
|
||||
Continue({})
|
||||
else
|
||||
|
@ -663,13 +663,13 @@ all = \list, predicate ->
|
|||
## list unaltered.
|
||||
##
|
||||
keep_if : List a, (a -> Bool) -> List a
|
||||
keep_if = \list, predicate ->
|
||||
keep_if = |list, predicate|
|
||||
length = List.len(list)
|
||||
|
||||
keep_if_help(list, predicate, 0, 0, length)
|
||||
|
||||
keep_if_help : List a, (a -> Bool), U64, U64, U64 -> List a
|
||||
keep_if_help = \list, predicate, kept, index, length ->
|
||||
keep_if_help = |list, predicate, kept, index, length|
|
||||
if index < length then
|
||||
if predicate(List.get_unsafe(list, index)) then
|
||||
keep_if_help(List.swap(list, kept, index), predicate, Num.add_wrap(kept, 1), Num.add_wrap(index, 1), length)
|
||||
|
@ -688,8 +688,8 @@ keep_if_help = \list, predicate, kept, index, length ->
|
|||
## `List.drop_if` has the same performance characteristics as [List.keep_if].
|
||||
## See its documentation for details on those characteristics!
|
||||
drop_if : List a, (a -> Bool) -> List a
|
||||
drop_if = \list, predicate ->
|
||||
List.keep_if(list, \e -> Bool.not(predicate(e)))
|
||||
drop_if = |list, predicate|
|
||||
List.keep_if(list, |e| Bool.not(predicate(e)))
|
||||
|
||||
## Run the given function on each element of a list, and return the
|
||||
## number of elements for which the function returned `Bool.true`.
|
||||
|
@ -698,8 +698,8 @@ drop_if = \list, predicate ->
|
|||
## expect List.count_if([1, 2, 3], (\num -> num > 1)) == 2
|
||||
## ```
|
||||
count_if : List a, (a -> Bool) -> U64
|
||||
count_if = \list, predicate ->
|
||||
walk_state = \state, elem ->
|
||||
count_if = |list, predicate|
|
||||
walk_state = |state, elem|
|
||||
if predicate(elem) then
|
||||
Num.add_wrap(state, 1)
|
||||
else
|
||||
|
@ -718,8 +718,8 @@ count_if = \list, predicate ->
|
|||
## expect List.keep_oks(["", "a", "bc", "", "d", "ef", ""], fn) == ["a", "bc", "d", "ef"]
|
||||
## ```
|
||||
keep_oks : List before, (before -> Result after *) -> List after
|
||||
keep_oks = \list, to_result ->
|
||||
walker = \accum, element ->
|
||||
keep_oks = |list, to_result|
|
||||
walker = |accum, element|
|
||||
when to_result(element) is
|
||||
Ok(keep) -> List.append(accum, keep)
|
||||
Err(_drop) -> accum
|
||||
|
@ -736,8 +736,8 @@ keep_oks = \list, to_result ->
|
|||
## List.keep_errs(["", "a", "bc", "", "d", "ef", ""], fn)
|
||||
## ```
|
||||
keep_errs : List before, (before -> Result * after) -> List after
|
||||
keep_errs = \list, to_result ->
|
||||
walker = \accum, element ->
|
||||
keep_errs = |list, to_result|
|
||||
walker = |accum, element|
|
||||
when to_result(element) is
|
||||
Ok(_drop) -> accum
|
||||
Err(keep) -> List.append(accum, keep)
|
||||
|
@ -752,14 +752,14 @@ keep_errs = \list, to_result ->
|
|||
## expect List.map(["", "a", "bc"], Str.is_empty) == [Bool.true, Bool.false, Bool.false]
|
||||
## ```
|
||||
map : List a, (a -> b) -> List b
|
||||
map = \list, mapper ->
|
||||
map = |list, mapper|
|
||||
# TODO: allow checking the refcounting and running the map inplace.
|
||||
# Preferably allow it even if the types are different (must be same size with padding though).
|
||||
length = List.len(list)
|
||||
List.walk(
|
||||
list,
|
||||
List.with_capacity(length),
|
||||
\state, elem ->
|
||||
|state, elem|
|
||||
List.append_unsafe(state, mapper(elem)),
|
||||
)
|
||||
|
||||
|
@ -773,12 +773,12 @@ map = \list, mapper ->
|
|||
## zipped = List.map2(["a", "b", "c"], [1, 2, 3], Pair)
|
||||
## ```
|
||||
map2 : List a, List b, (a, b -> c) -> List c
|
||||
map2 = \list_a, list_b, mapper ->
|
||||
map2 = |list_a, list_b, mapper|
|
||||
length = Num.min(List.len(list_a), List.len(list_b))
|
||||
map2_help(list_a, list_b, List.with_capacity(length), mapper, 0, length)
|
||||
|
||||
map2_help : List a, List b, List c, (a, b -> c), U64, U64 -> List c
|
||||
map2_help = \list_a, list_b, out, mapper, index, length ->
|
||||
map2_help = |list_a, list_b, out, mapper, index, length|
|
||||
if index < length then
|
||||
mapped = mapper(List.get_unsafe(list_a, index), List.get_unsafe(list_b, index))
|
||||
|
||||
|
@ -790,7 +790,7 @@ map2_help = \list_a, list_b, out, mapper, index, length ->
|
|||
## and use that as the first element in the returned list.
|
||||
## Repeat until a list runs out of elements.
|
||||
map3 : List a, List b, List c, (a, b, c -> d) -> List d
|
||||
map3 = \list_a, list_b, list_c, mapper ->
|
||||
map3 = |list_a, list_b, list_c, mapper|
|
||||
length = Num.min(
|
||||
Num.min(List.len(list_a), List.len(list_b)),
|
||||
List.len(list_c),
|
||||
|
@ -798,7 +798,7 @@ map3 = \list_a, list_b, list_c, mapper ->
|
|||
map3_help(list_a, list_b, list_c, List.with_capacity(length), mapper, 0, length)
|
||||
|
||||
map3_help : List a, List b, List c, List d, (a, b, c -> d), U64, U64 -> List d
|
||||
map3_help = \list_a, list_b, list_c, out, mapper, index, length ->
|
||||
map3_help = |list_a, list_b, list_c, out, mapper, index, length|
|
||||
if index < length then
|
||||
mapped = mapper(List.get_unsafe(list_a, index), List.get_unsafe(list_b, index), List.get_unsafe(list_c, index))
|
||||
|
||||
|
@ -810,7 +810,7 @@ map3_help = \list_a, list_b, list_c, out, mapper, index, length ->
|
|||
## and use that as the first element in the returned list.
|
||||
## Repeat until a list runs out of elements.
|
||||
map4 : List a, List b, List c, List d, (a, b, c, d -> e) -> List e
|
||||
map4 = \list_a, list_b, list_c, list_d, mapper ->
|
||||
map4 = |list_a, list_b, list_c, list_d, mapper|
|
||||
length = Num.min(
|
||||
Num.min(List.len(list_a), List.len(list_b)),
|
||||
Num.min(List.len(list_c), List.len(list_d)),
|
||||
|
@ -818,7 +818,7 @@ map4 = \list_a, list_b, list_c, list_d, mapper ->
|
|||
map4_help(list_a, list_b, list_c, list_d, List.with_capacity(length), mapper, 0, length)
|
||||
|
||||
map4_help : List a, List b, List c, List d, List e, (a, b, c, d -> e), U64, U64 -> List e
|
||||
map4_help = \list_a, list_b, list_c, list_d, out, mapper, index, length ->
|
||||
map4_help = |list_a, list_b, list_c, list_d, out, mapper, index, length|
|
||||
if index < length then
|
||||
mapped = mapper(List.get_unsafe(list_a, index), List.get_unsafe(list_b, index), List.get_unsafe(list_c, index), List.get_unsafe(list_d, index))
|
||||
|
||||
|
@ -832,7 +832,7 @@ map4_help = \list_a, list_b, list_c, list_d, out, mapper, index, length ->
|
|||
## expect List.map_with_index([10, 20, 30], (\num, index -> num + index)) == [10, 21, 32]
|
||||
## ```
|
||||
map_with_index : List a, (a, U64 -> b) -> List b
|
||||
map_with_index = \src, func ->
|
||||
map_with_index = |src, func|
|
||||
length = len(src)
|
||||
dest = with_capacity(length)
|
||||
|
||||
|
@ -840,7 +840,7 @@ map_with_index = \src, func ->
|
|||
|
||||
# Internal helper
|
||||
map_with_index_help : List a, List b, (a, U64 -> b), U64, U64 -> List b
|
||||
map_with_index_help = \src, dest, func, index, length ->
|
||||
map_with_index_help = |src, dest, func, index, length|
|
||||
if index < length then
|
||||
elem = get_unsafe(src, index)
|
||||
mapped_elem = func(elem, index)
|
||||
|
@ -875,30 +875,30 @@ map_with_index_help = \src, dest, func, index, length ->
|
|||
## All of these options are compatible with the others. For example, you can use `At` or `After`
|
||||
## with `start` regardless of what `end` and `step` are set to.
|
||||
range : _
|
||||
range = \{ start, end, step ?? 0 } ->
|
||||
range = |{ start, end, step ?? 0 }|
|
||||
{ calc_next, step_is_positive } =
|
||||
if step == 0 then
|
||||
when T(start, end) is
|
||||
T(At(x), At(y)) | T(At(x), Before(y)) | T(After(x), At(y)) | T(After(x), Before(y)) ->
|
||||
if x < y then
|
||||
{
|
||||
calc_next: \i -> Num.add_checked(i, 1),
|
||||
calc_next: |i| Num.add_checked(i, 1),
|
||||
step_is_positive: Bool.true,
|
||||
}
|
||||
else
|
||||
{
|
||||
calc_next: \i -> Num.sub_checked(i, 1),
|
||||
calc_next: |i| Num.sub_checked(i, 1),
|
||||
step_is_positive: Bool.false,
|
||||
}
|
||||
|
||||
T(At(_), Length(_)) | T(After(_), Length(_)) ->
|
||||
{
|
||||
calc_next: \i -> Num.add_checked(i, 1),
|
||||
calc_next: |i| Num.add_checked(i, 1),
|
||||
step_is_positive: Bool.true,
|
||||
}
|
||||
else
|
||||
{
|
||||
calc_next: \i -> Num.add_checked(i, step),
|
||||
calc_next: |i| Num.add_checked(i, step),
|
||||
step_is_positive: step > 0,
|
||||
}
|
||||
|
||||
|
@ -911,9 +911,9 @@ range = \{ start, end, step ?? 0 } ->
|
|||
At(at) ->
|
||||
is_valid =
|
||||
if step_is_positive then
|
||||
\i -> i <= at
|
||||
|i| i <= at
|
||||
else
|
||||
\i -> i >= at
|
||||
|i| i >= at
|
||||
|
||||
# TODO: switch to List.with_capacity
|
||||
range_help([], inclusive_start, calc_next, is_valid)
|
||||
|
@ -921,9 +921,9 @@ range = \{ start, end, step ?? 0 } ->
|
|||
Before(before) ->
|
||||
is_valid =
|
||||
if step_is_positive then
|
||||
\i -> i < before
|
||||
|i| i < before
|
||||
else
|
||||
\i -> i > before
|
||||
|i| i > before
|
||||
|
||||
# TODO: switch to List.with_capacity
|
||||
range_help([], inclusive_start, calc_next, is_valid)
|
||||
|
@ -931,7 +931,7 @@ range = \{ start, end, step ?? 0 } ->
|
|||
Length(l) ->
|
||||
range_length_help(List.with_capacity(l), inclusive_start, l, calc_next)
|
||||
|
||||
range_help = \accum, i, calc_next, is_valid ->
|
||||
range_help = |accum, i, calc_next, is_valid|
|
||||
when i is
|
||||
Ok(val) ->
|
||||
if is_valid(val) then
|
||||
|
@ -945,7 +945,7 @@ range_help = \accum, i, calc_next, is_valid ->
|
|||
# return the generated list.
|
||||
accum
|
||||
|
||||
range_length_help = \accum, i, remaining, calc_next ->
|
||||
range_length_help = |accum, i, remaining, calc_next|
|
||||
if remaining == 0 then
|
||||
accum
|
||||
else
|
||||
|
@ -1004,19 +1004,19 @@ sort_with : List a, (a, a -> [LT, EQ, GT]) -> List a
|
|||
##
|
||||
## To sort in descending order (highest to lowest), use [List.sort_desc] instead.
|
||||
sort_asc : List (Num a) -> List (Num a)
|
||||
sort_asc = \list -> List.sort_with(list, Num.compare)
|
||||
sort_asc = |list| List.sort_with(list, Num.compare)
|
||||
|
||||
## Sorts a list of numbers in descending order (highest to lowest).
|
||||
##
|
||||
## To sort in ascending order (lowest to highest), use [List.sort_asc] instead.
|
||||
sort_desc : List (Num a) -> List (Num a)
|
||||
sort_desc = \list -> List.sort_with(list, \a, b -> Num.compare(b, a))
|
||||
sort_desc = |list| List.sort_with(list, |a, b| Num.compare(b, a))
|
||||
|
||||
swap : List a, U64, U64 -> List a
|
||||
|
||||
## Returns the first element in the list, or `ListWasEmpty` if it was empty.
|
||||
first : List a -> Result a [ListWasEmpty]
|
||||
first = \list ->
|
||||
first = |list|
|
||||
when List.get(list, 0) is
|
||||
Ok(v) -> Ok(v)
|
||||
Err(_) -> Err(ListWasEmpty)
|
||||
|
@ -1038,7 +1038,7 @@ first = \list ->
|
|||
## To split the list into two lists, use `List.split_at`.
|
||||
##
|
||||
take_first : List elem, U64 -> List elem
|
||||
take_first = \list, output_length ->
|
||||
take_first = |list, output_length|
|
||||
List.sublist(list, { start: 0, len: output_length })
|
||||
|
||||
## Returns the given number of elements from the end of the list.
|
||||
|
@ -1058,19 +1058,19 @@ take_first = \list, output_length ->
|
|||
## To split the list into two lists, use `List.split_at`.
|
||||
##
|
||||
take_last : List elem, U64 -> List elem
|
||||
take_last = \list, output_length ->
|
||||
take_last = |list, output_length|
|
||||
List.sublist(list, { start: Num.sub_saturated(List.len(list), output_length), len: output_length })
|
||||
|
||||
## Drops n elements from the beginning of the list.
|
||||
drop_first : List elem, U64 -> List elem
|
||||
drop_first = \list, n ->
|
||||
drop_first = |list, n|
|
||||
remaining = Num.sub_saturated(List.len(list), n)
|
||||
|
||||
List.take_last(list, remaining)
|
||||
|
||||
## Drops n elements from the end of the list.
|
||||
drop_last : List elem, U64 -> List elem
|
||||
drop_last = \list, n ->
|
||||
drop_last = |list, n|
|
||||
remaining = Num.sub_saturated(List.len(list), n)
|
||||
|
||||
List.take_first(list, remaining)
|
||||
|
@ -1083,7 +1083,7 @@ drop_last = \list, n ->
|
|||
drop_at : List elem, U64 -> List elem
|
||||
|
||||
min : List (Num a) -> Result (Num a) [ListWasEmpty]
|
||||
min = \list ->
|
||||
min = |list|
|
||||
when List.first(list) is
|
||||
Ok(initial) ->
|
||||
Ok(min_help(list, initial))
|
||||
|
@ -1092,11 +1092,11 @@ min = \list ->
|
|||
Err(ListWasEmpty)
|
||||
|
||||
min_help : List (Num a), Num a -> Num a
|
||||
min_help = \list, initial ->
|
||||
min_help = |list, initial|
|
||||
List.walk(
|
||||
list,
|
||||
initial,
|
||||
\best_so_far, current ->
|
||||
|best_so_far, current|
|
||||
if current < best_so_far then
|
||||
current
|
||||
else
|
||||
|
@ -1104,7 +1104,7 @@ min_help = \list, initial ->
|
|||
)
|
||||
|
||||
max : List (Num a) -> Result (Num a) [ListWasEmpty]
|
||||
max = \list ->
|
||||
max = |list|
|
||||
when List.first(list) is
|
||||
Ok(initial) ->
|
||||
Ok(max_help(list, initial))
|
||||
|
@ -1113,11 +1113,11 @@ max = \list ->
|
|||
Err(ListWasEmpty)
|
||||
|
||||
max_help : List (Num a), Num a -> Num a
|
||||
max_help = \list, initial ->
|
||||
max_help = |list, initial|
|
||||
List.walk(
|
||||
list,
|
||||
initial,
|
||||
\best_so_far, current ->
|
||||
|best_so_far, current|
|
||||
if current > best_so_far then
|
||||
current
|
||||
else
|
||||
|
@ -1129,14 +1129,14 @@ max_help = \list, initial ->
|
|||
##
|
||||
## You may know a similar function named `concat_map` in other languages.
|
||||
join_map : List a, (a -> List b) -> List b
|
||||
join_map = \list, mapper ->
|
||||
List.walk(list, [], \state, elem -> List.concat(state, mapper(elem)))
|
||||
join_map = |list, mapper|
|
||||
List.walk(list, [], |state, elem| List.concat(state, mapper(elem)))
|
||||
|
||||
## Returns the first element of the list satisfying a predicate function.
|
||||
## If no satisfying element is found, an `Err NotFound` is returned.
|
||||
find_first : List elem, (elem -> Bool) -> Result elem [NotFound]
|
||||
find_first = \list, pred ->
|
||||
callback = \_, elem ->
|
||||
find_first = |list, pred|
|
||||
callback = |_, elem|
|
||||
if pred(elem) then
|
||||
Break(elem)
|
||||
else
|
||||
|
@ -1149,8 +1149,8 @@ find_first = \list, pred ->
|
|||
## Returns the last element of the list satisfying a predicate function.
|
||||
## If no satisfying element is found, an `Err NotFound` is returned.
|
||||
find_last : List elem, (elem -> Bool) -> Result elem [NotFound]
|
||||
find_last = \list, pred ->
|
||||
callback = \_, elem ->
|
||||
find_last = |list, pred|
|
||||
callback = |_, elem|
|
||||
if pred(elem) then
|
||||
Break(elem)
|
||||
else
|
||||
|
@ -1164,11 +1164,11 @@ find_last = \list, pred ->
|
|||
## satisfying a predicate function can be found.
|
||||
## If no satisfying element is found, an `Err NotFound` is returned.
|
||||
find_first_index : List elem, (elem -> Bool) -> Result U64 [NotFound]
|
||||
find_first_index = \list, matcher ->
|
||||
find_first_index = |list, matcher|
|
||||
found_index = List.iterate(
|
||||
list,
|
||||
0,
|
||||
\index, elem ->
|
||||
|index, elem|
|
||||
if matcher(elem) then
|
||||
Break(index)
|
||||
else
|
||||
|
@ -1183,11 +1183,11 @@ find_first_index = \list, matcher ->
|
|||
## satisfying a predicate function can be found.
|
||||
## If no satisfying element is found, an `Err NotFound` is returned.
|
||||
find_last_index : List elem, (elem -> Bool) -> Result U64 [NotFound]
|
||||
find_last_index = \list, matches ->
|
||||
find_last_index = |list, matches|
|
||||
found_index = List.iterate_backwards(
|
||||
list,
|
||||
List.len(list),
|
||||
\prev_index, elem ->
|
||||
|prev_index, elem|
|
||||
answer = Num.sub_wrap(prev_index, 1)
|
||||
|
||||
if matches(elem) then
|
||||
|
@ -1216,7 +1216,7 @@ find_last_index = \list, matches ->
|
|||
##
|
||||
## Some languages have a function called **`slice`** which works similarly to this.
|
||||
sublist : List elem, { start : U64, len : U64 } -> List elem
|
||||
sublist = \list, config ->
|
||||
sublist = |list, config|
|
||||
sublist_lowlevel(list, config.start, config.len)
|
||||
|
||||
## low-level slicing operation that does no bounds checking
|
||||
|
@ -1227,14 +1227,14 @@ sublist_lowlevel : List elem, U64, U64 -> List elem
|
|||
## List.intersperse([1, 2, 3], 9) == [1, 9, 2, 9, 3]
|
||||
## ```
|
||||
intersperse : List elem, elem -> List elem
|
||||
intersperse = \list, sep ->
|
||||
intersperse = |list, sep|
|
||||
capacity = 2 * List.len(list)
|
||||
init = List.with_capacity(capacity)
|
||||
new_list =
|
||||
List.walk(
|
||||
list,
|
||||
init,
|
||||
\acc, elem ->
|
||||
|acc, elem|
|
||||
acc
|
||||
|> List.append_unsafe(elem)
|
||||
|> List.append_unsafe(sep),
|
||||
|
@ -1249,7 +1249,7 @@ intersperse = \list, sep ->
|
|||
##
|
||||
## If the first list is empty, this only returns `Bool.true` if the second list is empty.
|
||||
starts_with : List elem, List elem -> Bool where elem implements Eq
|
||||
starts_with = \list, prefix ->
|
||||
starts_with = |list, prefix|
|
||||
# TODO once we have seamless slices, verify that this wouldn't
|
||||
# have better performance with a function like List.compare_sublists
|
||||
prefix == List.sublist(list, { start: 0, len: List.len(prefix) })
|
||||
|
@ -1261,7 +1261,7 @@ starts_with = \list, prefix ->
|
|||
##
|
||||
## If the first list is empty, this only returns `Bool.true` if the second list is empty.
|
||||
ends_with : List elem, List elem -> Bool where elem implements Eq
|
||||
ends_with = \list, suffix ->
|
||||
ends_with = |list, suffix|
|
||||
# TODO once we have seamless slices, verify that this wouldn't
|
||||
# have better performance with a function like List.compare_sublists
|
||||
length = List.len(suffix)
|
||||
|
@ -1277,7 +1277,7 @@ ends_with = \list, suffix ->
|
|||
## means if you give an index of 0, the `before` list will be empty and the
|
||||
## `others` list will have the same elements as the original list.)
|
||||
split_at : List elem, U64 -> { before : List elem, others : List elem }
|
||||
split_at = \elements, user_split_index ->
|
||||
split_at = |elements, user_split_index|
|
||||
length = List.len(elements)
|
||||
split_index = if length > user_split_index then user_split_index else length
|
||||
before = List.sublist(elements, { start: 0, len: split_index })
|
||||
|
@ -1291,8 +1291,8 @@ split_at = \elements, user_split_index ->
|
|||
## List.split_on([1, 2, 3], 2) == [[1], [3]]
|
||||
## ```
|
||||
split_on : List a, a -> List (List a) where a implements Eq
|
||||
split_on = \elements, delimiter ->
|
||||
help = \remaining, chunks, current_chunk ->
|
||||
split_on = |elements, delimiter|
|
||||
help = |remaining, chunks, current_chunk|
|
||||
when remaining is
|
||||
[] -> List.append(chunks, current_chunk)
|
||||
[x, .. as rest] if x == delimiter ->
|
||||
|
@ -1308,8 +1308,8 @@ split_on = \elements, delimiter ->
|
|||
## List.split_on_list([1, 2, 3], [1, 2]) == [[], [3]]
|
||||
## ```
|
||||
split_on_list : List a, List a -> List (List a) where a implements Eq
|
||||
split_on_list = \elements, delimiter ->
|
||||
help = \remaining, chunks, current_chunk ->
|
||||
split_on_list = |elements, delimiter|
|
||||
help = |remaining, chunks, current_chunk|
|
||||
when remaining is
|
||||
[] -> List.append(chunks, current_chunk)
|
||||
[x, .. as rest] ->
|
||||
|
@ -1329,8 +1329,8 @@ split_on_list = \elements, delimiter ->
|
|||
## List.split_first([Foo, Z, Bar, Z, Baz], Z) == Ok({ before: [Foo], after: [Bar, Z, Baz] })
|
||||
## ```
|
||||
split_first : List elem, elem -> Result { before : List elem, after : List elem } [NotFound] where elem implements Eq
|
||||
split_first = \list, delimiter ->
|
||||
when List.find_first_index(list, \elem -> elem == delimiter) is
|
||||
split_first = |list, delimiter|
|
||||
when List.find_first_index(list, |elem| elem == delimiter) is
|
||||
Ok(index) ->
|
||||
before = List.sublist(list, { start: 0, len: index })
|
||||
after = List.sublist(list, { start: Num.add_wrap(index, 1), len: Num.sub_wrap(List.len(list), index) |> Num.sub_wrap(1) })
|
||||
|
@ -1345,8 +1345,8 @@ split_first = \list, delimiter ->
|
|||
## List.split_last([Foo, Z, Bar, Z, Baz], Z) == Ok({ before: [Foo, Z, Bar], after: [Baz] })
|
||||
## ```
|
||||
split_last : List elem, elem -> Result { before : List elem, after : List elem } [NotFound] where elem implements Eq
|
||||
split_last = \list, delimiter ->
|
||||
when List.find_last_index(list, \elem -> elem == delimiter) is
|
||||
split_last = |list, delimiter|
|
||||
when List.find_last_index(list, |elem| elem == delimiter) is
|
||||
Ok(index) ->
|
||||
before = List.sublist(list, { start: 0, len: index })
|
||||
after = List.sublist(list, { start: Num.add_wrap(index, 1), len: Num.sub_wrap(List.len(list), index) |> Num.sub_wrap(1) })
|
||||
|
@ -1360,15 +1360,15 @@ split_last = \list, delimiter ->
|
|||
## chunk size. If the provided list is empty or if the chunk size is 0 then the
|
||||
## result is an empty list.
|
||||
chunks_of : List a, U64 -> List (List a)
|
||||
chunks_of = \list, chunk_size ->
|
||||
if chunk_size == 0 || List.is_empty(list) then
|
||||
chunks_of = |list, chunk_size|
|
||||
if chunk_size == 0 or List.is_empty(list) then
|
||||
[]
|
||||
else
|
||||
chunk_capacity = Num.div_ceil(List.len(list), chunk_size)
|
||||
chunks_of_help(list, chunk_size, List.with_capacity(chunk_capacity))
|
||||
|
||||
chunks_of_help : List a, U64, List (List a) -> List (List a)
|
||||
chunks_of_help = \list_rest, chunk_size, chunks ->
|
||||
chunks_of_help = |list_rest, chunk_size, chunks|
|
||||
if List.is_empty(list_rest) then
|
||||
chunks
|
||||
else
|
||||
|
@ -1379,14 +1379,14 @@ chunks_of_help = \list_rest, chunk_size, chunks ->
|
|||
## If that function ever returns `Err`, [map_try] immediately returns that `Err`.
|
||||
## If it returns `Ok` for every element, [map_try] returns `Ok` with the transformed list.
|
||||
map_try : List elem, (elem -> Result ok err) -> Result (List ok) err
|
||||
map_try = \list, to_result ->
|
||||
map_try = |list, to_result|
|
||||
walk_try(
|
||||
list,
|
||||
[],
|
||||
\state, elem ->
|
||||
|state, elem|
|
||||
Result.map_ok(
|
||||
to_result(elem),
|
||||
\ok ->
|
||||
|ok|
|
||||
List.append(state, ok),
|
||||
),
|
||||
)
|
||||
|
@ -1403,12 +1403,12 @@ map_try = \list, to_result ->
|
|||
## As such, it is typically better for performance to use this over [List.walk]
|
||||
## if returning `Break` earlier than the last element is expected to be common.
|
||||
walk_try : List elem, state, (state, elem -> Result state err) -> Result state err
|
||||
walk_try = \list, init, func ->
|
||||
walk_try = |list, init, func|
|
||||
walk_try_help(list, init, func, 0, List.len(list))
|
||||
|
||||
## internal helper
|
||||
walk_try_help : List elem, state, (state, elem -> Result state err), U64, U64 -> Result state err
|
||||
walk_try_help = \list, state, f, index, length ->
|
||||
walk_try_help = |list, state, f, index, length|
|
||||
if index < length then
|
||||
when f(state, List.get_unsafe(list, index)) is
|
||||
Ok(next_state) -> walk_try_help(list, next_state, f, Num.add_wrap(index, 1), length)
|
||||
|
@ -1418,12 +1418,12 @@ walk_try_help = \list, state, f, index, length ->
|
|||
|
||||
## Primitive for iterating over a List, being able to decide at every element whether to continue
|
||||
iterate : List elem, s, (s, elem -> [Continue s, Break b]) -> [Continue s, Break b]
|
||||
iterate = \list, init, func ->
|
||||
iterate = |list, init, func|
|
||||
iter_help(list, init, func, 0, List.len(list))
|
||||
|
||||
## internal helper
|
||||
iter_help : List elem, s, (s, elem -> [Continue s, Break b]), U64, U64 -> [Continue s, Break b]
|
||||
iter_help = \list, state, f, index, length ->
|
||||
iter_help = |list, state, f, index, length|
|
||||
if index < length then
|
||||
when f(state, List.get_unsafe(list, index)) is
|
||||
Continue(next_state) -> iter_help(list, next_state, f, Num.add_wrap(index, 1), length)
|
||||
|
@ -1434,12 +1434,12 @@ iter_help = \list, state, f, index, length ->
|
|||
## Primitive for iterating over a List from back to front, being able to decide at every
|
||||
## element whether to continue
|
||||
iterate_backwards : List elem, s, (s, elem -> [Continue s, Break b]) -> [Continue s, Break b]
|
||||
iterate_backwards = \list, init, func ->
|
||||
iterate_backwards = |list, init, func|
|
||||
iter_backwards_help(list, init, func, List.len(list))
|
||||
|
||||
## internal helper
|
||||
iter_backwards_help : List elem, s, (s, elem -> [Continue s, Break b]), U64 -> [Continue s, Break b]
|
||||
iter_backwards_help = \list, state, f, prev_index ->
|
||||
iter_backwards_help = |list, state, f, prev_index|
|
||||
if prev_index > 0 then
|
||||
index = Num.sub_wrap(prev_index, 1)
|
||||
|
||||
|
@ -1468,7 +1468,7 @@ expect (List.concat_utf8([1, 2, 3, 4], "🐦")) == [1, 2, 3, 4, 240, 159, 144, 1
|
|||
##
|
||||
## If the function might fail or you need to return early, use [for_each_try!].
|
||||
for_each! : List a, (a => {}) => {}
|
||||
for_each! = \list, func! ->
|
||||
for_each! = |list, func!|
|
||||
when list is
|
||||
[] ->
|
||||
{}
|
||||
|
@ -1489,7 +1489,7 @@ for_each! = \list, func! ->
|
|||
## )
|
||||
## ```
|
||||
for_each_try! : List a, (a => Result {} err) => Result {} err
|
||||
for_each_try! = \list, func! ->
|
||||
for_each_try! = |list, func!|
|
||||
when list is
|
||||
[] ->
|
||||
Ok({})
|
||||
|
@ -1513,7 +1513,7 @@ for_each_try! = \list, func! ->
|
|||
##
|
||||
## This is the same as [walk], except that the step function can have effects.
|
||||
walk! : List elem, state, (state, elem => state) => state
|
||||
walk! = \list, state, func! ->
|
||||
walk! = |list, state, func!|
|
||||
when list is
|
||||
[] ->
|
||||
state
|
||||
|
@ -1540,7 +1540,7 @@ walk! = \list, state, func! ->
|
|||
##
|
||||
## This is the same as [walk_try], except that the step function can have effects.
|
||||
walk_try! : List elem, state, (state, elem => Result state err) => Result state err
|
||||
walk_try! = \list, state, func! ->
|
||||
walk_try! = |list, state, func!|
|
||||
when list is
|
||||
[] ->
|
||||
Ok(state)
|
||||
|
|
|
@ -532,7 +532,7 @@ pi = 3.14159265358979323846264338327950288419716939937510
|
|||
|
||||
## Circle constant (τ)
|
||||
tau : Frac *
|
||||
tau = 2 * pi
|
||||
tau = 6.2831853071795864769252867665590057683943387987502
|
||||
|
||||
# ------- Functions
|
||||
## Convert a number to a [Str].
|
||||
|
@ -618,10 +618,10 @@ is_gte : Num a, Num a -> Bool
|
|||
## If either argument is [*NaN*](Num.is_nan), returns `Bool.false` no matter what. (*NaN*
|
||||
## is [defined to be unordered](https://en.wikipedia.org/wiki/NaN#Comparison_with_NaN).)
|
||||
is_approx_eq : Frac a, Frac a, { rtol ?? Frac a, atol ?? Frac a } -> Bool
|
||||
is_approx_eq = \x, y, { rtol ?? 0.00001, atol ?? 0.00000001 } ->
|
||||
eq = x <= y && x >= y
|
||||
is_approx_eq = |x, y, { rtol ?? 0.00001, atol ?? 0.00000001 }|
|
||||
eq = x <= y and x >= y
|
||||
meets_tolerance = Num.abs_diff(x, y) <= Num.max(atol, (rtol * Num.max(Num.abs(x), Num.abs(y))))
|
||||
eq || meets_tolerance
|
||||
eq or meets_tolerance
|
||||
|
||||
## Returns `Bool.true` if the number is `0`, and `Bool.false` otherwise.
|
||||
is_zero : Num a -> Bool
|
||||
|
@ -630,21 +630,21 @@ is_zero : Num a -> Bool
|
|||
##
|
||||
## Examples of even numbers: 0, 2, 4, 6, 8, -2, -4, -6, -8
|
||||
is_even : Int a -> Bool
|
||||
is_even = \x -> Num.is_multiple_of(x, 2)
|
||||
is_even = |x| Num.is_multiple_of(x, 2)
|
||||
|
||||
## A number is odd if dividing it by 2 gives a remainder of 1.
|
||||
##
|
||||
## Examples of odd numbers: 1, 3, 5, 7, -1, -3, -5, -7
|
||||
is_odd : Int a -> Bool
|
||||
is_odd = \x -> Bool.not(Num.is_multiple_of(x, 2))
|
||||
is_odd = |x| Bool.not(Num.is_multiple_of(x, 2))
|
||||
|
||||
## Positive numbers are greater than `0`.
|
||||
is_positive : Num a -> Bool
|
||||
is_positive = \x -> x > 0
|
||||
is_positive = |x| x > 0
|
||||
|
||||
## Negative numbers are less than `0`.
|
||||
is_negative : Num a -> Bool
|
||||
is_negative = \x -> x < 0
|
||||
is_negative = |x| x < 0
|
||||
|
||||
to_frac : Num * -> Frac *
|
||||
|
||||
|
@ -709,7 +709,7 @@ abs : Num a -> Num a
|
|||
## *overflow*. For [F64] and [F32], overflow results in an answer of either
|
||||
## ∞ or -∞. For all other number types, overflow results in a panic.
|
||||
abs_diff : Num a, Num a -> Num a
|
||||
abs_diff = \a, b ->
|
||||
abs_diff = |a, b|
|
||||
if a > b then
|
||||
a - b
|
||||
else
|
||||
|
@ -812,7 +812,7 @@ mul : Num a, Num a -> Num a
|
|||
## Num.min(3.0, -3.0)
|
||||
## ```
|
||||
min : Num a, Num a -> Num a
|
||||
min = \a, b ->
|
||||
min = |a, b|
|
||||
if a < b then
|
||||
a
|
||||
else
|
||||
|
@ -826,7 +826,7 @@ min = \a, b ->
|
|||
## Num.max(3.0, -3.0)
|
||||
## ```
|
||||
max : Num a, Num a -> Num a
|
||||
max = \a, b ->
|
||||
max = |a, b|
|
||||
if a > b then
|
||||
a
|
||||
else
|
||||
|
@ -868,7 +868,7 @@ atan : Frac a -> Frac a
|
|||
sqrt : Frac a -> Frac a
|
||||
|
||||
sqrt_checked : Frac a -> Result (Frac a) [SqrtOfNegative]
|
||||
sqrt_checked = \x ->
|
||||
sqrt_checked = |x|
|
||||
if x < 0.0 then
|
||||
Err(SqrtOfNegative)
|
||||
else
|
||||
|
@ -878,7 +878,7 @@ sqrt_checked = \x ->
|
|||
log : Frac a -> Frac a
|
||||
|
||||
log_checked : Frac a -> Result (Frac a) [LogNeedsPositive]
|
||||
log_checked = \x ->
|
||||
log_checked = |x|
|
||||
if x <= 0.0 then
|
||||
Err(LogNeedsPositive)
|
||||
else
|
||||
|
@ -918,7 +918,7 @@ log_checked = \x ->
|
|||
div : Frac a, Frac a -> Frac a
|
||||
|
||||
div_checked : Frac a, Frac a -> Result (Frac a) [DivByZero]
|
||||
div_checked = \a, b ->
|
||||
div_checked = |a, b|
|
||||
if Num.is_zero(b) then
|
||||
Err(DivByZero)
|
||||
else
|
||||
|
@ -927,7 +927,7 @@ div_checked = \a, b ->
|
|||
div_ceil : Int a, Int a -> Int a
|
||||
|
||||
div_ceil_checked : Int a, Int a -> Result (Int a) [DivByZero]
|
||||
div_ceil_checked = \a, b ->
|
||||
div_ceil_checked = |a, b|
|
||||
if Num.is_zero(b) then
|
||||
Err(DivByZero)
|
||||
else
|
||||
|
@ -950,14 +950,14 @@ div_ceil_checked = \a, b ->
|
|||
## Num.div_trunc(8, -3)
|
||||
## ```
|
||||
div_trunc : Int a, Int a -> Int a
|
||||
div_trunc = \a, b ->
|
||||
div_trunc = |a, b|
|
||||
if Num.is_zero(b) then
|
||||
crash("Integer division by 0!")
|
||||
else
|
||||
Num.div_trunc_unchecked(a, b)
|
||||
|
||||
div_trunc_checked : Int a, Int a -> Result (Int a) [DivByZero]
|
||||
div_trunc_checked = \a, b ->
|
||||
div_trunc_checked = |a, b|
|
||||
if Num.is_zero(b) then
|
||||
Err(DivByZero)
|
||||
else
|
||||
|
@ -979,14 +979,14 @@ div_trunc_unchecked : Int a, Int a -> Int a
|
|||
## Num.rem(-8, -3)
|
||||
## ```
|
||||
rem : Int a, Int a -> Int a
|
||||
rem = \a, b ->
|
||||
rem = |a, b|
|
||||
if Num.is_zero(b) then
|
||||
crash("Integer division by 0!")
|
||||
else
|
||||
Num.rem_unchecked(a, b)
|
||||
|
||||
rem_checked : Int a, Int a -> Result (Int a) [DivByZero]
|
||||
rem_checked = \a, b ->
|
||||
rem_checked = |a, b|
|
||||
if Num.is_zero(b) then
|
||||
Err(DivByZero)
|
||||
else
|
||||
|
@ -1013,7 +1013,7 @@ bitwise_or : Int a, Int a -> Int a
|
|||
## Returns the complement of x - the number you get by switching each 1 for a
|
||||
## 0 and each 0 for a 1. This is the same as -x - 1.
|
||||
bitwise_not : Int a -> Int a
|
||||
bitwise_not = \n ->
|
||||
bitwise_not = |n|
|
||||
bitwise_xor(n, sub_wrap(0, 1))
|
||||
|
||||
## Bitwise left shift of a number by another
|
||||
|
@ -1134,7 +1134,7 @@ add_saturated : Num a, Num a -> Num a
|
|||
## This is the same as [Num.add] except if the operation overflows, instead of
|
||||
## panicking or returning ∞ or -∞, it will return `Err Overflow`.
|
||||
add_checked : Num a, Num a -> Result (Num a) [Overflow]
|
||||
add_checked = \a, b ->
|
||||
add_checked = |a, b|
|
||||
result = add_checked_lowlevel(a, b)
|
||||
|
||||
if result.b then
|
||||
|
@ -1160,7 +1160,7 @@ sub_saturated : Num a, Num a -> Num a
|
|||
## This is the same as [Num.sub] except if the operation overflows, instead of
|
||||
## panicking or returning ∞ or -∞, it will return `Err Overflow`.
|
||||
sub_checked : Num a, Num a -> Result (Num a) [Overflow]
|
||||
sub_checked = \a, b ->
|
||||
sub_checked = |a, b|
|
||||
result = sub_checked_lowlevel(a, b)
|
||||
|
||||
if result.b then
|
||||
|
@ -1184,7 +1184,7 @@ mul_saturated : Num a, Num a -> Num a
|
|||
## This is the same as [Num.mul] except if the operation overflows, instead of
|
||||
## panicking or returning ∞ or -∞, it will return `Err Overflow`.
|
||||
mul_checked : Num a, Num a -> Result (Num a) [Overflow]
|
||||
mul_checked = \a, b ->
|
||||
mul_checked = |a, b|
|
||||
result = mul_checked_lowlevel(a, b)
|
||||
|
||||
if result.b then
|
||||
|
@ -1464,7 +1464,7 @@ f64_from_parts : { sign : Bool, exponent : U16, fraction : U64 } -> F64
|
|||
## expect Num.from_bool(Bool.false) == 0
|
||||
## ```
|
||||
from_bool : Bool -> Num *
|
||||
from_bool = \bool ->
|
||||
from_bool = |bool|
|
||||
if bool then
|
||||
1
|
||||
else
|
||||
|
|
|
@ -23,7 +23,7 @@ Result ok err : [Ok ok, Err err]
|
|||
## Result.is_ok(Ok(5))
|
||||
## ```
|
||||
is_ok : Result ok err -> Bool
|
||||
is_ok = \result ->
|
||||
is_ok = |result|
|
||||
when result is
|
||||
Ok(_) -> Bool.true
|
||||
Err(_) -> Bool.false
|
||||
|
@ -33,7 +33,7 @@ is_ok = \result ->
|
|||
## Result.is_err(Err("uh oh"))
|
||||
## ```
|
||||
is_err : Result ok err -> Bool
|
||||
is_err = \result ->
|
||||
is_err = |result|
|
||||
when result is
|
||||
Ok(_) -> Bool.false
|
||||
Err(_) -> Bool.true
|
||||
|
@ -45,7 +45,7 @@ is_err = \result ->
|
|||
## Result.with_default(Err("uh oh"), 42)
|
||||
## ```
|
||||
with_default : Result ok err, ok -> ok
|
||||
with_default = \result, default ->
|
||||
with_default = |result, default|
|
||||
when result is
|
||||
Ok(value) -> value
|
||||
Err(_) -> default
|
||||
|
@ -61,7 +61,7 @@ with_default = \result, default ->
|
|||
## Functions like `map` are common in Roc; see for example [List.map],
|
||||
## `Set.map`, and `Dict.map`.
|
||||
map_ok : Result a err, (a -> b) -> Result b err
|
||||
map_ok = \result, transform ->
|
||||
map_ok = |result, transform|
|
||||
when result is
|
||||
Ok(v) -> Ok(transform(v))
|
||||
Err(e) -> Err(e)
|
||||
|
@ -74,14 +74,14 @@ map_ok = \result, transform ->
|
|||
## Result.map_err(Ok(12), Str.is_empty)
|
||||
## ```
|
||||
map_err : Result ok a, (a -> b) -> Result ok b
|
||||
map_err = \result, transform ->
|
||||
map_err = |result, transform|
|
||||
when result is
|
||||
Ok(v) -> Ok(v)
|
||||
Err(e) -> Err(transform(e))
|
||||
|
||||
## Maps both the `Ok` and `Err` values of a `Result` to new values.
|
||||
map_both : Result ok1 err1, (ok1 -> ok2), (err1 -> err2) -> Result ok2 err2
|
||||
map_both = \result, ok_transform, err_transform ->
|
||||
map_both = |result, ok_transform, err_transform|
|
||||
when result is
|
||||
Ok(val) -> Ok(ok_transform(val))
|
||||
Err(err) -> Err(err_transform(err))
|
||||
|
@ -89,7 +89,7 @@ map_both = \result, ok_transform, err_transform ->
|
|||
## Maps the `Ok` values of two `Result`s to a new value using a given transformation,
|
||||
## or returns the first `Err` value encountered.
|
||||
map2 : Result a err, Result b err, (a, b -> c) -> Result c err
|
||||
map2 = \first_result, second_result, transform ->
|
||||
map2 = |first_result, second_result, transform|
|
||||
when (first_result, second_result) is
|
||||
(Ok(first), Ok(second)) -> Ok(transform(first, second))
|
||||
(Err(err), _) -> Err(err)
|
||||
|
@ -103,7 +103,7 @@ map2 = \first_result, second_result, transform ->
|
|||
## Result.try(Err("yipes!"), (\num -> if num < 0 then Err("negative!") else Ok(-num)))
|
||||
## ```
|
||||
try : Result a err, (a -> Result b err) -> Result b err
|
||||
try = \result, transform ->
|
||||
try = |result, transform|
|
||||
when result is
|
||||
Ok(v) -> transform(v)
|
||||
Err(e) -> Err(e)
|
||||
|
@ -116,7 +116,7 @@ try = \result, transform ->
|
|||
## Result.on_err(Err("42"), (\error_num -> Str.to_u64(error_num)))
|
||||
## ```
|
||||
on_err : Result a err, (err -> Result a other_err) -> Result a other_err
|
||||
on_err = \result, transform ->
|
||||
on_err = |result, transform|
|
||||
when result is
|
||||
Ok(v) -> Ok(v)
|
||||
Err(e) -> transform(e)
|
||||
|
@ -132,7 +132,7 @@ on_err = \result, transform ->
|
|||
## )
|
||||
## ```
|
||||
on_err! : Result a err, (err => Result a other_err) => Result a other_err
|
||||
on_err! = \result, transform! ->
|
||||
on_err! = |result, transform!|
|
||||
when result is
|
||||
Ok(v) -> Ok(v)
|
||||
Err(e) -> transform!(e)
|
||||
|
|
|
@ -47,14 +47,14 @@ Set k := Dict.Dict k {} where k implements Hash & Eq
|
|||
]
|
||||
|
||||
is_eq : Set k, Set k -> Bool
|
||||
is_eq = \xs, ys ->
|
||||
is_eq = |xs, ys|
|
||||
if len(xs) != len(ys) then
|
||||
Bool.false
|
||||
else
|
||||
walk_until(
|
||||
xs,
|
||||
Bool.true,
|
||||
\_, elem ->
|
||||
|_, elem|
|
||||
if contains(ys, elem) then
|
||||
Continue(Bool.true)
|
||||
else
|
||||
|
@ -62,12 +62,12 @@ is_eq = \xs, ys ->
|
|||
)
|
||||
|
||||
hash_set : hasher, Set k -> hasher where hasher implements Hasher
|
||||
hash_set = \hasher, @Set(inner) -> Hash.hash(hasher, inner)
|
||||
hash_set = |hasher, @Set(inner)| Hash.hash(hasher, inner)
|
||||
|
||||
to_inspector_set : Set k -> Inspector f where k implements Inspect & Hash & Eq, f implements InspectFormatter
|
||||
to_inspector_set = \set ->
|
||||
to_inspector_set = |set|
|
||||
Inspect.custom(
|
||||
\fmt ->
|
||||
|fmt|
|
||||
Inspect.apply(Inspect.set(set, walk, Inspect.to_inspector), fmt),
|
||||
)
|
||||
|
||||
|
@ -79,25 +79,25 @@ to_inspector_set = \set ->
|
|||
## expect count_values == 0
|
||||
## ```
|
||||
empty : {} -> Set *
|
||||
empty = \{} -> @Set(Dict.empty({}))
|
||||
empty = |{}| @Set(Dict.empty({}))
|
||||
|
||||
## Return a set with space allocated for a number of entries. This
|
||||
## may provide a performance optimization if you know how many entries will be
|
||||
## inserted.
|
||||
with_capacity : U64 -> Set *
|
||||
with_capacity = \cap ->
|
||||
with_capacity = |cap|
|
||||
@Set(Dict.with_capacity(cap))
|
||||
|
||||
## Enlarge the set for at least capacity additional elements
|
||||
reserve : Set k, U64 -> Set k
|
||||
reserve = \@Set(dict), requested ->
|
||||
reserve = |@Set(dict), requested|
|
||||
@Set(Dict.reserve(dict, requested))
|
||||
|
||||
## Shrink the memory footprint of a set such that capacity is as small as possible.
|
||||
## This function will require regenerating the metadata if the size changes.
|
||||
## There will still be some overhead due to dictionary metadata always being a power of 2.
|
||||
release_excess_capacity : Set k -> Set k
|
||||
release_excess_capacity = \@Set(dict) ->
|
||||
release_excess_capacity = |@Set(dict)|
|
||||
@Set(Dict.release_excess_capacity(dict))
|
||||
|
||||
## Creates a new `Set` with a single value.
|
||||
|
@ -108,7 +108,7 @@ release_excess_capacity = \@Set(dict) ->
|
|||
## expect count_values == 1
|
||||
## ```
|
||||
single : k -> Set k
|
||||
single = \key ->
|
||||
single = |key|
|
||||
Dict.single(key, {}) |> @Set
|
||||
|
||||
## Insert a value into a `Set`.
|
||||
|
@ -124,7 +124,7 @@ single = \key ->
|
|||
## expect count_values == 3
|
||||
## ```
|
||||
insert : Set k, k -> Set k
|
||||
insert = \@Set(dict), key ->
|
||||
insert = |@Set(dict), key|
|
||||
Dict.insert(dict, key, {}) |> @Set
|
||||
|
||||
# Inserting a duplicate key has no effect.
|
||||
|
@ -157,7 +157,7 @@ expect
|
|||
## expect count_values == 3
|
||||
## ```
|
||||
len : Set * -> U64
|
||||
len = \@Set(dict) ->
|
||||
len = |@Set(dict)|
|
||||
Dict.len(dict)
|
||||
|
||||
## Returns the max number of elements the set can hold before requiring a rehash.
|
||||
|
@ -169,7 +169,7 @@ len = \@Set(dict) ->
|
|||
## capacity_of_set = Set.capacity(food_set)
|
||||
## ```
|
||||
capacity : Set * -> U64
|
||||
capacity = \@Set(dict) ->
|
||||
capacity = |@Set(dict)|
|
||||
Dict.capacity(dict)
|
||||
|
||||
## Check if the set is empty.
|
||||
|
@ -179,7 +179,7 @@ capacity = \@Set(dict) ->
|
|||
## Set.is_empty(Set.empty({}))
|
||||
## ```
|
||||
is_empty : Set * -> Bool
|
||||
is_empty = \@Set(dict) ->
|
||||
is_empty = |@Set(dict)|
|
||||
Dict.is_empty(dict)
|
||||
|
||||
# Inserting a duplicate key has no effect on length.
|
||||
|
@ -209,7 +209,7 @@ expect
|
|||
## expect has20 == Bool.true
|
||||
## ```
|
||||
remove : Set k, k -> Set k
|
||||
remove = \@Set(dict), key ->
|
||||
remove = |@Set(dict), key|
|
||||
Dict.remove(dict, key) |> @Set
|
||||
|
||||
## Test if a value is in the `Set`.
|
||||
|
@ -228,7 +228,7 @@ remove = \@Set(dict), key ->
|
|||
## expect has_banana == Bool.false
|
||||
## ```
|
||||
contains : Set k, k -> Bool
|
||||
contains = \@Set(dict), key ->
|
||||
contains = |@Set(dict), key|
|
||||
Dict.contains(dict, key)
|
||||
|
||||
## Retrieve the values in a `Set` as a `List`.
|
||||
|
@ -241,7 +241,7 @@ contains = \@Set(dict), key ->
|
|||
## expect Set.to_list(numbers) == values
|
||||
## ```
|
||||
to_list : Set k -> List k
|
||||
to_list = \@Set(dict) ->
|
||||
to_list = |@Set(dict)|
|
||||
Dict.keys(dict)
|
||||
|
||||
## Create a `Set` from a `List` of values.
|
||||
|
@ -255,9 +255,9 @@ to_list = \@Set(dict) ->
|
|||
## expect Set.from_list([Pear, Apple, Banana]) == values
|
||||
## ```
|
||||
from_list : List k -> Set k
|
||||
from_list = \list ->
|
||||
from_list = |list|
|
||||
list
|
||||
|> List.map(\k -> (k, {}))
|
||||
|> List.map(|k| (k, {}))
|
||||
|> Dict.from_list
|
||||
|> @Set
|
||||
|
||||
|
@ -272,7 +272,7 @@ from_list = \list ->
|
|||
## expect Set.union(set1, set2) == Set.from_list([Left, Right])
|
||||
## ```
|
||||
union : Set k, Set k -> Set k
|
||||
union = \@Set(dict1), @Set(dict2) ->
|
||||
union = |@Set(dict1), @Set(dict2)|
|
||||
Dict.insert_all(dict1, dict2) |> @Set
|
||||
|
||||
## Combine two `Set`s by keeping the [intersection](https://en.wikipedia.org/wiki/Intersection_(set_theory))
|
||||
|
@ -285,7 +285,7 @@ union = \@Set(dict1), @Set(dict2) ->
|
|||
## expect Set.intersection(set1, set2) == Set.single(Left)
|
||||
## ```
|
||||
intersection : Set k, Set k -> Set k
|
||||
intersection = \@Set(dict1), @Set(dict2) ->
|
||||
intersection = |@Set(dict1), @Set(dict2)|
|
||||
Dict.keep_shared(dict1, dict2) |> @Set
|
||||
|
||||
## Remove the values in the first `Set` that are also in the second `Set`
|
||||
|
@ -299,7 +299,7 @@ intersection = \@Set(dict1), @Set(dict2) ->
|
|||
## expect Set.difference(first, second) == Set.from_list([Up, Down])
|
||||
## ```
|
||||
difference : Set k, Set k -> Set k
|
||||
difference = \@Set(dict1), @Set(dict2) ->
|
||||
difference = |@Set(dict1), @Set(dict2)|
|
||||
Dict.remove_all(dict1, dict2) |> @Set
|
||||
|
||||
## Iterate through the values of a given `Set` and build a value.
|
||||
|
@ -322,20 +322,20 @@ difference = \@Set(dict1), @Set(dict2) ->
|
|||
## expect result == 2
|
||||
## ```
|
||||
walk : Set k, state, (state, k -> state) -> state
|
||||
walk = \@Set(dict), state, step ->
|
||||
Dict.walk(dict, state, \s, k, _ -> step(s, k))
|
||||
walk = |@Set(dict), state, step|
|
||||
Dict.walk(dict, state, |s, k, _| step(s, k))
|
||||
|
||||
## Convert each value in the set to something new, by calling a conversion
|
||||
## function on each of them which receives the old value. Then return a
|
||||
## new set containing the converted values.
|
||||
map : Set a, (a -> b) -> Set b
|
||||
map = \set, transform ->
|
||||
map = |set, transform|
|
||||
init = with_capacity(capacity(set))
|
||||
|
||||
walk(
|
||||
set,
|
||||
init,
|
||||
\answer, k ->
|
||||
|answer, k|
|
||||
insert(answer, transform(k)),
|
||||
)
|
||||
|
||||
|
@ -345,13 +345,13 @@ map = \set, transform ->
|
|||
##
|
||||
## You may know a similar function named `concat_map` in other languages.
|
||||
join_map : Set a, (a -> Set b) -> Set b
|
||||
join_map = \set, transform ->
|
||||
join_map = |set, transform|
|
||||
init = with_capacity(capacity(set)) # Might be a pessimization
|
||||
|
||||
walk(
|
||||
set,
|
||||
init,
|
||||
\answer, k ->
|
||||
|answer, k|
|
||||
union(answer, transform(k)),
|
||||
)
|
||||
|
||||
|
@ -371,8 +371,8 @@ join_map = \set, transform ->
|
|||
## expect result == FoundTheAnswer
|
||||
## ```
|
||||
walk_until : Set k, state, (state, k -> [Continue state, Break state]) -> state
|
||||
walk_until = \@Set(dict), state, step ->
|
||||
Dict.walk_until(dict, state, \s, k, _ -> step(s, k))
|
||||
walk_until = |@Set(dict), state, step|
|
||||
Dict.walk_until(dict, state, |s, k, _| step(s, k))
|
||||
|
||||
## Run the given function on each element in the `Set`, and return
|
||||
## a `Set` with just the elements for which the function returned `Bool.true`.
|
||||
|
@ -382,8 +382,8 @@ walk_until = \@Set(dict), state, step ->
|
|||
## |> Bool.is_eq(Set.from_list([3,4,5]))
|
||||
## ```
|
||||
keep_if : Set k, (k -> Bool) -> Set k
|
||||
keep_if = \@Set(dict), predicate ->
|
||||
@Set(Dict.keep_if(dict, \(k, _v) -> predicate(k)))
|
||||
keep_if = |@Set(dict), predicate|
|
||||
@Set(Dict.keep_if(dict, |(k, _v)| predicate(k)))
|
||||
|
||||
## Run the given function on each element in the `Set`, and return
|
||||
## a `Set` with just the elements for which the function returned `Bool.false`.
|
||||
|
@ -393,8 +393,8 @@ keep_if = \@Set(dict), predicate ->
|
|||
## |> Bool.is_eq(Set.from_list([1,2]))
|
||||
## ```
|
||||
drop_if : Set k, (k -> Bool) -> Set k
|
||||
drop_if = \@Set(dict), predicate ->
|
||||
@Set(Dict.drop_if(dict, \(k, _v) -> predicate(k)))
|
||||
drop_if = |@Set(dict), predicate|
|
||||
@Set(Dict.drop_if(dict, |(k, _v)| predicate(k)))
|
||||
|
||||
expect
|
||||
first =
|
||||
|
@ -498,10 +498,10 @@ expect
|
|||
|
||||
expect
|
||||
Set.from_list([1, 2, 3, 4, 5])
|
||||
|> Set.keep_if(\k -> k >= 3)
|
||||
|> Set.keep_if(|k| k >= 3)
|
||||
|> Bool.is_eq(Set.from_list([3, 4, 5]))
|
||||
|
||||
expect
|
||||
Set.from_list([1, 2, 3, 4, 5])
|
||||
|> Set.drop_if(\k -> k >= 3)
|
||||
|> Set.drop_if(|k| k >= 3)
|
||||
|> Bool.is_eq(Set.from_list([1, 2]))
|
||||
|
|
|
@ -328,7 +328,6 @@
|
|||
## Currently, the only way to get seamless slices of strings is by calling certain `Str` functions which return them. In general, `Str` functions which accept a string and return a subset of that string tend to do this. [`Str.trim`](https://www.roc-lang.org/builtins/Str#trim) is another example of a function which returns a seamless slice.
|
||||
module [
|
||||
Utf8Problem,
|
||||
Utf8ByteProblem,
|
||||
concat,
|
||||
is_empty,
|
||||
join_with,
|
||||
|
@ -337,6 +336,11 @@ module [
|
|||
count_utf8_bytes,
|
||||
to_utf8,
|
||||
from_utf8,
|
||||
from_utf16,
|
||||
from_utf32,
|
||||
from_utf8_lossy,
|
||||
from_utf16_lossy,
|
||||
from_utf32_lossy,
|
||||
starts_with,
|
||||
ends_with,
|
||||
trim,
|
||||
|
@ -369,6 +373,9 @@ module [
|
|||
contains,
|
||||
drop_prefix,
|
||||
drop_suffix,
|
||||
with_ascii_lowercased,
|
||||
with_ascii_uppercased,
|
||||
caseless_ascii_equals,
|
||||
]
|
||||
|
||||
import Bool exposing [Bool]
|
||||
|
@ -376,7 +383,7 @@ import Result exposing [Result]
|
|||
import List
|
||||
import Num exposing [Num, U8, U16, U32, U64, U128, I8, I16, I32, I64, I128, F32, F64, Dec]
|
||||
|
||||
Utf8ByteProblem : [
|
||||
Utf8Problem : [
|
||||
InvalidStartByte,
|
||||
UnexpectedEndOfSequence,
|
||||
ExpectedContinuation,
|
||||
|
@ -385,8 +392,6 @@ Utf8ByteProblem : [
|
|||
EncodesSurrogateHalf,
|
||||
]
|
||||
|
||||
Utf8Problem : { byte_index : U64, problem : Utf8ByteProblem }
|
||||
|
||||
## Returns [Bool.true] if the string is empty, and [Bool.false] otherwise.
|
||||
## ```roc
|
||||
## expect Str.is_empty("hi!") == Bool.false
|
||||
|
@ -538,8 +543,8 @@ to_utf8 : Str -> List U8
|
|||
## expect Str.from_utf8([]) == Ok("")
|
||||
## expect Str.from_utf8([255]) |> Result.is_err
|
||||
## ```
|
||||
from_utf8 : List U8 -> Result Str [BadUtf8 { problem : Utf8ByteProblem, index : U64 }]
|
||||
from_utf8 = \bytes ->
|
||||
from_utf8 : List U8 -> Result Str [BadUtf8 { problem : Utf8Problem, index : U64 }]
|
||||
from_utf8 = |bytes|
|
||||
result = from_utf8_lowlevel bytes
|
||||
|
||||
if result.c_is_ok then
|
||||
|
@ -557,11 +562,242 @@ FromUtf8Result : {
|
|||
a_byte_index : U64,
|
||||
b_string : Str,
|
||||
c_is_ok : Bool,
|
||||
d_problem_code : Utf8ByteProblem,
|
||||
d_problem_code : Utf8Problem,
|
||||
}
|
||||
|
||||
from_utf8_lowlevel : List U8 -> FromUtf8Result
|
||||
|
||||
## Converts a [List] of [U8] UTF-8 [code units](https://unicode.org/glossary/#code_unit) to a string.
|
||||
## Any grouping of invalid byte sequences are replaced with a single unicode replacement character '<27>'.
|
||||
##
|
||||
## An invalid byte sequence is defined as
|
||||
## - a 2-byte-sequence starting byte, followed by less than 1 continuation byte
|
||||
## - a 3-byte-sequence starting byte, followed by less than 2 continuation bytes
|
||||
## - a 4-byte-sequence starting byte, followed by less than 3 continuation bytes
|
||||
## - an invalid codepoint from the surrogate pair block
|
||||
## - an invalid codepoint greater than 0x110000 encoded as a 4-byte sequence
|
||||
## - any valid codepoint encoded as an incorrect sequence, for instance a codepoint that should be a 2-byte sequence encoded as a 3- or 4-byte sequence
|
||||
##
|
||||
## ```roc
|
||||
## expect (Str.from_utf8_lossy [82, 111, 99, 240, 159, 144, 166]) == "Roc🐦"
|
||||
## expect (Str.from_utf8_lossy [82, 255, 99]) == "R<>c"
|
||||
## expect (Str.from_utf8_lossy [82, 0xED, 0xA0, 0xBD, 99]) == "R<>c"
|
||||
## ```
|
||||
from_utf8_lossy : List U8 -> Str
|
||||
|
||||
expect (Str.from_utf8_lossy [82, 111, 99, 240, 159, 144, 166]) == "Roc🐦"
|
||||
expect (Str.from_utf8_lossy [82, 255, 99]) == "R<>c"
|
||||
expect (Str.from_utf8_lossy [82, 0xED, 0xA0, 0xBD, 99]) == "R<>c"
|
||||
|
||||
## Converts a [List] of [U16] UTF-16 (little-endian) [code units](https://unicode.org/glossary/#code_unit) to a string.
|
||||
##
|
||||
## ```roc
|
||||
## expect Str.from_utf16([82, 111, 99]) == Ok("Roc")
|
||||
## expect Str.from_utf16([0xb9a, 0xbbf]) == Ok("சி")
|
||||
## expect Str.from_utf16([0xd83d, 0xdc26]) == Ok("🐦")
|
||||
## expect Str.from_utf16([]) == Ok("")
|
||||
## # unpaired surrogates, first and second halves
|
||||
## expect Str.from_utf16([82, 0xd83d, 99]) |> Result.isErr
|
||||
## expect Str.from_utf16([82, 0xdc96, 99]) |> Result.isErr
|
||||
## ```
|
||||
from_utf16 : List U16 -> Result Str [BadUtf16 { problem : Utf8Problem, index : U64 }]
|
||||
from_utf16 = |codeunits|
|
||||
mk_err = |problem, index|
|
||||
Err(BadUtf16({ problem, index }))
|
||||
|
||||
step = |state, unit|
|
||||
c : U32
|
||||
c = Num.int_cast(unit)
|
||||
when state is
|
||||
ExpectFirst(i, utf8) ->
|
||||
if unit < 0xd800 then
|
||||
when encode_utf8(utf8, c) is
|
||||
Ok(utf8_next) -> ExpectFirst(i + 1, utf8_next)
|
||||
Err(err) -> mk_err(err, i)
|
||||
else
|
||||
ExpectSecond(i, utf8, c)
|
||||
|
||||
ExpectSecond(i, utf8, first) ->
|
||||
if unit < 0xdc00 then
|
||||
mk_err(EncodesSurrogateHalf, i)
|
||||
else
|
||||
joined = ((first - 0xd800) * 0x400) + (c - 0xdc00) + 0x10000
|
||||
when encode_utf8(utf8, joined) is
|
||||
Ok(utf8_next) -> ExpectFirst(i + 2, utf8_next)
|
||||
Err(err) -> mk_err(err, i)
|
||||
|
||||
Err(err) -> Err(err)
|
||||
|
||||
decode_res = List.walk(codeunits, ExpectFirst(0, []), step)
|
||||
|
||||
when decode_res is
|
||||
ExpectFirst(_, utf8) ->
|
||||
from_utf8(utf8)
|
||||
|> Result.map_err(|BadUtf8(err)| BadUtf16(err))
|
||||
|
||||
ExpectSecond(i, _, _) ->
|
||||
mk_err(EncodesSurrogateHalf, i)
|
||||
|
||||
Err(err) -> Err(err)
|
||||
|
||||
expect Str.from_utf16([82, 111, 99]) == Ok("Roc")
|
||||
expect Str.from_utf16([0xb9a, 0xbbf]) == Ok("சி")
|
||||
expect Str.from_utf16([0xd83d, 0xdc26]) == Ok("🐦")
|
||||
expect Str.from_utf16([]) == Ok("")
|
||||
# unpaired surrogates, first and second halves
|
||||
expect Str.from_utf16([82, 0xd83d, 99]) == Err(BadUtf16({ index: 1, problem: EncodesSurrogateHalf }))
|
||||
expect Str.from_utf16([82, 0xdc96, 99]) == Err(BadUtf16({ index: 1, problem: EncodesSurrogateHalf }))
|
||||
|
||||
## Converts a [List] of [U16] UTF-16 (little-endian) [code units](https://unicode.org/glossary/#code_unit) to a string.
|
||||
## Any unpaired surrogate code unit is replaced with a single unicode replacement character '<27>'.
|
||||
##
|
||||
## ```roc
|
||||
## expect Str.from_utf16_lossy([82, 111, 99, 0xd83d, 0xdc26]) == "Roc🐦"
|
||||
## expect Str.from_utf16_lossy([82, 0xdc96, 99]) == "R<>c"
|
||||
## ```
|
||||
from_utf16_lossy : List U16 -> Str
|
||||
from_utf16_lossy = |codeunits|
|
||||
utf8_replacement = [0xef, 0xbf, 0xbd]
|
||||
encode_lossy = |utf8, c|
|
||||
when encode_utf8(utf8, c) is
|
||||
Ok(utf8_next) -> utf8_next
|
||||
Err(_) -> List.concat(utf8, utf8_replacement)
|
||||
|
||||
step = |state, unit|
|
||||
c : U32
|
||||
c = Num.int_cast(unit)
|
||||
when state is
|
||||
ExpectFirst(utf8) ->
|
||||
if unit < 0xd800 then
|
||||
ExpectFirst(encode_lossy(utf8, c))
|
||||
else
|
||||
ExpectSecond(utf8, c)
|
||||
|
||||
ExpectSecond(utf8, first) ->
|
||||
if c < 0xd800 then
|
||||
ExpectFirst(
|
||||
List.concat(utf8, utf8_replacement)
|
||||
|> encode_lossy(c),
|
||||
)
|
||||
else if c < 0xdc00 then
|
||||
ExpectSecond(List.concat(utf8, utf8_replacement), c)
|
||||
else
|
||||
joined = ((first - 0xd800) * 0x400) + (c - 0xdc00) + 0x10000
|
||||
ExpectFirst(encode_lossy(utf8, joined))
|
||||
|
||||
result = List.walk(codeunits, ExpectFirst([]), step)
|
||||
when result is
|
||||
ExpectFirst(utf8) -> from_utf8_lossy(utf8)
|
||||
ExpectSecond(utf8, _) -> from_utf8_lossy(List.concat(utf8, utf8_replacement))
|
||||
|
||||
expect Str.from_utf16_lossy([82, 111, 99, 0xd83d, 0xdc26]) == "Roc🐦"
|
||||
expect Str.from_utf16_lossy([82, 0xdc96, 99]) == "R<>c"
|
||||
|
||||
## Converts a [List] of [U32] UTF-32 [code units](https://unicode.org/glossary/#code_unit) to a string.
|
||||
##
|
||||
## ```roc
|
||||
## expect Str.from_utf32([82, 111, 99]) == Ok("Roc")
|
||||
## expect Str.from_utf32([0xb9a, 0xbbf]) == Ok("சி")
|
||||
## expect Str.from_utf32([0x1f426]) == Ok("🐦")
|
||||
## # unpaired surrogates, first and second halves
|
||||
## expect Str.from_utf32([82, 0xd83d, 99]) |> Result.isErr
|
||||
## expect Str.from_utf32([82, 0xdc96, 99]) |> Result.isErr
|
||||
## # invalid codepoint
|
||||
## expect Str.from_utf32([82, 0x110000, 99]) |> Result.isErr
|
||||
## ```
|
||||
|
||||
from_utf32 : List U32 -> Result Str [BadUtf32 { problem : Utf8Problem, index : U64 }]
|
||||
from_utf32 = |codepoints|
|
||||
step = |state, c|
|
||||
when state is
|
||||
Ok({ i, utf8 }) ->
|
||||
when encode_utf8(utf8, c) is
|
||||
Ok(utf8_next) -> Ok({ i: i + 1, utf8: utf8_next })
|
||||
Err(problem) -> Err(BadUtf32({ problem, index: i }))
|
||||
|
||||
Err(err) -> Err(err)
|
||||
|
||||
List.walk(codepoints, Ok({ i: 0, utf8: [] }), step)
|
||||
|> Result.try(
|
||||
|state|
|
||||
when from_utf8(state.utf8) is
|
||||
Ok(str) -> Ok(str)
|
||||
Err(BadUtf8(err)) -> Err(BadUtf32(err)),
|
||||
)
|
||||
|
||||
encode_utf8 : List U8, U32 -> Result (List U8) [EncodesSurrogateHalf, CodepointTooLarge]
|
||||
encode_utf8 = |list, c|
|
||||
if c < 0x80 then
|
||||
Ok(List.append(list, Num.int_cast(c)))
|
||||
else if c < 0x800 then
|
||||
Ok(
|
||||
List.concat(
|
||||
list,
|
||||
[
|
||||
Num.int_cast(Num.bitwise_or(Num.shift_right_by(c, 6), 0b110_00000)),
|
||||
Num.int_cast(Num.bitwise_or(Num.bitwise_and(c, 0b111111), 0b10_000000)),
|
||||
],
|
||||
),
|
||||
)
|
||||
else if c < 0x10000 then
|
||||
if (c >= 0xd800) and (c < 0xe000) then
|
||||
Err(EncodesSurrogateHalf)
|
||||
else
|
||||
Ok(
|
||||
List.concat(
|
||||
list,
|
||||
[
|
||||
Num.int_cast(Num.bitwise_or(Num.shift_right_by(c, 12), 0b1110_0000)),
|
||||
Num.int_cast(Num.bitwise_or(Num.bitwise_and(Num.shift_right_by(c, 6), 0b111111), 0b10_000000)),
|
||||
Num.int_cast(Num.bitwise_or(Num.bitwise_and(c, 0b111111), 0b10_000000)),
|
||||
],
|
||||
),
|
||||
)
|
||||
else if c < 0x110000 then
|
||||
Ok(
|
||||
List.concat(
|
||||
list,
|
||||
[
|
||||
Num.int_cast(Num.bitwise_or(Num.shift_right_by(c, 18), 0b11110_000)),
|
||||
Num.int_cast(Num.bitwise_or(Num.bitwise_and(Num.shift_right_by(c, 12), 0b111111), 0b10_000000)),
|
||||
Num.int_cast(Num.bitwise_or(Num.bitwise_and(Num.shift_right_by(c, 6), 0b111111), 0b10_000000)),
|
||||
Num.int_cast(Num.bitwise_or(Num.bitwise_and(c, 0b111111), 0b10_000000)),
|
||||
],
|
||||
),
|
||||
)
|
||||
else
|
||||
Err(CodepointTooLarge)
|
||||
|
||||
expect Str.from_utf32([82, 111, 99]) == Ok("Roc")
|
||||
expect Str.from_utf32([0xb9a, 0xbbf]) == Ok("சி")
|
||||
expect Str.from_utf32([0x1f426]) == Ok("🐦")
|
||||
expect Str.from_utf32([]) == Ok("")
|
||||
# unpaired surrogates, first and second halves
|
||||
expect Str.from_utf32([82, 0xd83d, 99]) |> Result.is_err
|
||||
expect Str.from_utf32([82, 0xdc96, 99]) |> Result.is_err
|
||||
# codepoint out of valid range
|
||||
expect Str.from_utf32([82, 0x110000, 99]) |> Result.is_err
|
||||
|
||||
## Converts a [List] of [U32] UTF-32 [code units](https://unicode.org/glossary/#code_unit) to a string.
|
||||
## Any invalid code points are replaced with a single unicode replacement character '<27>'.
|
||||
## ```roc
|
||||
## expect Str.from_utf32_lossy([82, 111, 99, 0x1f426]) == "Roc🐦"
|
||||
## expect Str.from_utf32_lossy([82, 0x110000, 99]) == "R<>c"
|
||||
## ```
|
||||
from_utf32_lossy : List U32 -> Str
|
||||
from_utf32_lossy = |codepoints|
|
||||
step = |utf8, c|
|
||||
when encode_utf8(utf8, c) is
|
||||
Ok(utf8_next) -> utf8_next
|
||||
# utf-8 encoded replacement character
|
||||
Err(_) -> List.concat(utf8, [0xef, 0xbf, 0xbd])
|
||||
|
||||
List.walk(codepoints, [], step)
|
||||
|> from_utf8_lossy()
|
||||
|
||||
expect Str.from_utf32_lossy([82, 111, 99, 0x1f426]) == "Roc🐦"
|
||||
expect Str.from_utf32_lossy([82, 0x110000, 99]) == "R<>c"
|
||||
|
||||
## Check if the given [Str] starts with a value.
|
||||
## ```roc
|
||||
## expect Str.starts_with("ABC", "A") == Bool.true
|
||||
|
@ -603,7 +839,7 @@ trim_end : Str -> Str
|
|||
## expect Str.to_dec("not a number") == Err(InvalidNumStr)
|
||||
## ```
|
||||
to_dec : Str -> Result Dec [InvalidNumStr]
|
||||
to_dec = \string -> str_to_num_help(string)
|
||||
to_dec = |string| str_to_num_help(string)
|
||||
|
||||
## Encode a [Str] to a [F64]. A [F64] value is a 64-bit
|
||||
## [floating-point number](https://en.wikipedia.org/wiki/IEEE_754) and can be
|
||||
|
@ -613,7 +849,7 @@ to_dec = \string -> str_to_num_help(string)
|
|||
## expect Str.to_f64("not a number") == Err(InvalidNumStr)
|
||||
## ```
|
||||
to_f64 : Str -> Result F64 [InvalidNumStr]
|
||||
to_f64 = \string -> str_to_num_help(string)
|
||||
to_f64 = |string| str_to_num_help(string)
|
||||
|
||||
## Encode a [Str] to a [F32].A [F32] value is a 32-bit
|
||||
## [floating-point number](https://en.wikipedia.org/wiki/IEEE_754) and can be
|
||||
|
@ -623,7 +859,7 @@ to_f64 = \string -> str_to_num_help(string)
|
|||
## expect Str.to_f32("not a number") == Err(InvalidNumStr)
|
||||
## ```
|
||||
to_f32 : Str -> Result F32 [InvalidNumStr]
|
||||
to_f32 = \string -> str_to_num_help(string)
|
||||
to_f32 = |string| str_to_num_help(string)
|
||||
|
||||
## Encode a [Str] to an unsigned [U128] integer. A [U128] value can hold numbers
|
||||
## from `0` to `340_282_366_920_938_463_463_374_607_431_768_211_455` (over
|
||||
|
@ -635,7 +871,7 @@ to_f32 = \string -> str_to_num_help(string)
|
|||
## expect Str.to_u128("not a number") == Err(InvalidNumStr)
|
||||
## ```
|
||||
to_u128 : Str -> Result U128 [InvalidNumStr]
|
||||
to_u128 = \string -> str_to_num_help(string)
|
||||
to_u128 = |string| str_to_num_help(string)
|
||||
|
||||
## Encode a [Str] to a signed [I128] integer. A [I128] value can hold numbers
|
||||
## from `-170_141_183_460_469_231_731_687_303_715_884_105_728` to
|
||||
|
@ -648,7 +884,7 @@ to_u128 = \string -> str_to_num_help(string)
|
|||
## expect Str.to_i128("not a number") == Err(InvalidNumStr)
|
||||
## ```
|
||||
to_i128 : Str -> Result I128 [InvalidNumStr]
|
||||
to_i128 = \string -> str_to_num_help(string)
|
||||
to_i128 = |string| str_to_num_help(string)
|
||||
|
||||
## Encode a [Str] to an unsigned [U64] integer. A [U64] value can hold numbers
|
||||
## from `0` to `18_446_744_073_709_551_615` (over 18 quintillion). It
|
||||
|
@ -660,7 +896,7 @@ to_i128 = \string -> str_to_num_help(string)
|
|||
## expect Str.to_u64("not a number") == Err(InvalidNumStr)
|
||||
## ```
|
||||
to_u64 : Str -> Result U64 [InvalidNumStr]
|
||||
to_u64 = \string -> str_to_num_help(string)
|
||||
to_u64 = |string| str_to_num_help(string)
|
||||
|
||||
## Encode a [Str] to a signed [I64] integer. A [I64] value can hold numbers
|
||||
## from `-9_223_372_036_854_775_808` to `9_223_372_036_854_775_807`. It can be
|
||||
|
@ -672,7 +908,7 @@ to_u64 = \string -> str_to_num_help(string)
|
|||
## expect Str.to_i64("not a number") == Err(InvalidNumStr)
|
||||
## ```
|
||||
to_i64 : Str -> Result I64 [InvalidNumStr]
|
||||
to_i64 = \string -> str_to_num_help(string)
|
||||
to_i64 = |string| str_to_num_help(string)
|
||||
|
||||
## Encode a [Str] to an unsigned [U32] integer. A [U32] value can hold numbers
|
||||
## from `0` to `4_294_967_295` (over 4 billion). It can be specified with
|
||||
|
@ -684,7 +920,7 @@ to_i64 = \string -> str_to_num_help(string)
|
|||
## expect Str.to_u32("not a number") == Err(InvalidNumStr)
|
||||
## ```
|
||||
to_u32 : Str -> Result U32 [InvalidNumStr]
|
||||
to_u32 = \string -> str_to_num_help(string)
|
||||
to_u32 = |string| str_to_num_help(string)
|
||||
|
||||
## Encode a [Str] to a signed [I32] integer. A [I32] value can hold numbers
|
||||
## from `-2_147_483_648` to `2_147_483_647`. It can be
|
||||
|
@ -696,7 +932,7 @@ to_u32 = \string -> str_to_num_help(string)
|
|||
## expect Str.to_i32("not a number") == Err(InvalidNumStr)
|
||||
## ```
|
||||
to_i32 : Str -> Result I32 [InvalidNumStr]
|
||||
to_i32 = \string -> str_to_num_help(string)
|
||||
to_i32 = |string| str_to_num_help(string)
|
||||
|
||||
## Encode a [Str] to an unsigned [U16] integer. A [U16] value can hold numbers
|
||||
## from `0` to `65_535`. It can be specified with a u16 suffix.
|
||||
|
@ -707,7 +943,7 @@ to_i32 = \string -> str_to_num_help(string)
|
|||
## expect Str.to_u16("not a number") == Err(InvalidNumStr)
|
||||
## ```
|
||||
to_u16 : Str -> Result U16 [InvalidNumStr]
|
||||
to_u16 = \string -> str_to_num_help(string)
|
||||
to_u16 = |string| str_to_num_help(string)
|
||||
|
||||
## Encode a [Str] to a signed [I16] integer. A [I16] value can hold numbers
|
||||
## from `-32_768` to `32_767`. It can be
|
||||
|
@ -719,7 +955,7 @@ to_u16 = \string -> str_to_num_help(string)
|
|||
## expect Str.to_i16("not a number") == Err(InvalidNumStr)
|
||||
## ```
|
||||
to_i16 : Str -> Result I16 [InvalidNumStr]
|
||||
to_i16 = \string -> str_to_num_help(string)
|
||||
to_i16 = |string| str_to_num_help(string)
|
||||
|
||||
## Encode a [Str] to an unsigned [U8] integer. A [U8] value can hold numbers
|
||||
## from `0` to `255`. It can be specified with a u8 suffix.
|
||||
|
@ -730,7 +966,7 @@ to_i16 = \string -> str_to_num_help(string)
|
|||
## expect Str.to_u8("1500") == Err(InvalidNumStr)
|
||||
## ```
|
||||
to_u8 : Str -> Result U8 [InvalidNumStr]
|
||||
to_u8 = \string -> str_to_num_help(string)
|
||||
to_u8 = |string| str_to_num_help(string)
|
||||
|
||||
## Encode a [Str] to a signed [I8] integer. A [I8] value can hold numbers
|
||||
## from `-128` to `127`. It can be
|
||||
|
@ -741,7 +977,7 @@ to_u8 = \string -> str_to_num_help(string)
|
|||
## expect Str.to_i8("not a number") == Err(InvalidNumStr)
|
||||
## ```
|
||||
to_i8 : Str -> Result I8 [InvalidNumStr]
|
||||
to_i8 = \string -> str_to_num_help(string)
|
||||
to_i8 = |string| str_to_num_help(string)
|
||||
|
||||
## Get the byte at the given index, without performing a bounds check.
|
||||
get_unsafe : Str, U64 -> U8
|
||||
|
@ -763,7 +999,7 @@ substring_unsafe : Str, U64, U64 -> Str
|
|||
## expect Str.replace_each("not here", "/", "_") == "not here"
|
||||
## ```
|
||||
replace_each : Str, Str, Str -> Str
|
||||
replace_each = \haystack, needle, flower ->
|
||||
replace_each = |haystack, needle, flower|
|
||||
when split_first(haystack, needle) is
|
||||
Ok({ before, after }) ->
|
||||
# We found at least one needle, so start the buffer off with
|
||||
|
@ -776,7 +1012,7 @@ replace_each = \haystack, needle, flower ->
|
|||
Err(NotFound) -> haystack
|
||||
|
||||
replace_each_help : Str, Str, Str, Str -> Str
|
||||
replace_each_help = \buf, haystack, needle, flower ->
|
||||
replace_each_help = |buf, haystack, needle, flower|
|
||||
when split_first(haystack, needle) is
|
||||
Ok({ before, after }) ->
|
||||
buf
|
||||
|
@ -797,7 +1033,7 @@ expect Str.replace_each("abcdefg", "nothing", "_") == "abcdefg"
|
|||
## expect Str.replace_first("no slashes here", "/", "_") == "no slashes here"
|
||||
## ```
|
||||
replace_first : Str, Str, Str -> Str
|
||||
replace_first = \haystack, needle, flower ->
|
||||
replace_first = |haystack, needle, flower|
|
||||
when split_first(haystack, needle) is
|
||||
Ok({ before, after }) ->
|
||||
"${before}${flower}${after}"
|
||||
|
@ -815,7 +1051,7 @@ expect Str.replace_first("abcdefg", "nothing", "_") == "abcdefg"
|
|||
## expect Str.replace_last("no slashes here", "/", "_") == "no slashes here"
|
||||
## ```
|
||||
replace_last : Str, Str, Str -> Str
|
||||
replace_last = \haystack, needle, flower ->
|
||||
replace_last = |haystack, needle, flower|
|
||||
when split_last(haystack, needle) is
|
||||
Ok({ before, after }) ->
|
||||
"${before}${flower}${after}"
|
||||
|
@ -833,7 +1069,7 @@ expect Str.replace_last("abcdefg", "nothing", "_") == "abcdefg"
|
|||
## expect Str.split_first("no slashes here", "/") == Err(NotFound)
|
||||
## ```
|
||||
split_first : Str, Str -> Result { before : Str, after : Str } [NotFound]
|
||||
split_first = \haystack, needle ->
|
||||
split_first = |haystack, needle|
|
||||
when first_match(haystack, needle) is
|
||||
Some(index) ->
|
||||
remaining = Str.count_utf8_bytes(haystack) - Str.count_utf8_bytes(needle) - index
|
||||
|
@ -862,7 +1098,7 @@ expect split_first("hullabaloo", "ab") == Ok({ before: "hull", after: "aloo" })
|
|||
expect split_first("foo", "foo") == Ok({ before: "", after: "" })
|
||||
|
||||
first_match : Str, Str -> [Some U64, None]
|
||||
first_match = \haystack, needle ->
|
||||
first_match = |haystack, needle|
|
||||
haystack_length = Str.count_utf8_bytes(haystack)
|
||||
needle_length = Str.count_utf8_bytes(needle)
|
||||
last_possible = Num.sub_saturated(haystack_length, needle_length)
|
||||
|
@ -870,7 +1106,7 @@ first_match = \haystack, needle ->
|
|||
first_match_help(haystack, needle, 0, last_possible)
|
||||
|
||||
first_match_help : Str, Str, U64, U64 -> [Some U64, None]
|
||||
first_match_help = \haystack, needle, index, last_possible ->
|
||||
first_match_help = |haystack, needle, index, last_possible|
|
||||
if index <= last_possible then
|
||||
if matches_at(haystack, index, needle) then
|
||||
Some(index)
|
||||
|
@ -887,7 +1123,7 @@ first_match_help = \haystack, needle, index, last_possible ->
|
|||
## expect Str.split_last("no slashes here", "/") == Err(NotFound)
|
||||
## ```
|
||||
split_last : Str, Str -> Result { before : Str, after : Str } [NotFound]
|
||||
split_last = \haystack, needle ->
|
||||
split_last = |haystack, needle|
|
||||
when last_match(haystack, needle) is
|
||||
Some(index) ->
|
||||
remaining = Str.count_utf8_bytes(haystack) - Str.count_utf8_bytes(needle) - index
|
||||
|
@ -913,7 +1149,7 @@ expect Str.split_last("hullabaloo", "ab") == Ok({ before: "hull", after: "aloo"
|
|||
expect Str.split_last("foo", "foo") == Ok({ before: "", after: "" })
|
||||
|
||||
last_match : Str, Str -> [Some U64, None]
|
||||
last_match = \haystack, needle ->
|
||||
last_match = |haystack, needle|
|
||||
haystack_length = Str.count_utf8_bytes(haystack)
|
||||
needle_length = Str.count_utf8_bytes(needle)
|
||||
last_possible_index = Num.sub_saturated(haystack_length, needle_length)
|
||||
|
@ -921,7 +1157,7 @@ last_match = \haystack, needle ->
|
|||
last_match_help(haystack, needle, last_possible_index)
|
||||
|
||||
last_match_help : Str, Str, U64 -> [Some U64, None]
|
||||
last_match_help = \haystack, needle, index ->
|
||||
last_match_help = |haystack, needle, index|
|
||||
if matches_at(haystack, index, needle) then
|
||||
Some(index)
|
||||
else
|
||||
|
@ -932,10 +1168,10 @@ last_match_help = \haystack, needle, index ->
|
|||
Err(_) ->
|
||||
None
|
||||
|
||||
min = \x, y -> if x < y then x else y
|
||||
min = |x, y| if x < y then x else y
|
||||
|
||||
matches_at : Str, U64, Str -> Bool
|
||||
matches_at = \haystack, haystack_index, needle ->
|
||||
matches_at = |haystack, haystack_index, needle|
|
||||
haystack_length = Str.count_utf8_bytes(haystack)
|
||||
needle_length = Str.count_utf8_bytes(needle)
|
||||
end_index = min(Num.add_saturated(haystack_index, needle_length), haystack_length)
|
||||
|
@ -951,7 +1187,7 @@ matches_at = \haystack, haystack_index, needle ->
|
|||
},
|
||||
)
|
||||
|
||||
matches_at_help = \state ->
|
||||
matches_at_help = |state|
|
||||
{ haystack, haystack_index, needle, needle_index, needle_length, end_index } = state
|
||||
is_at_end_of_haystack = haystack_index >= end_index
|
||||
|
||||
|
@ -972,7 +1208,7 @@ matches_at_help = \state ->
|
|||
},
|
||||
)
|
||||
|
||||
does_this_match && does_rest_match
|
||||
does_this_match and does_rest_match
|
||||
|
||||
## Walks over the `UTF-8` bytes of the given [Str] and calls a function to update
|
||||
## state for each byte. The index for that byte in the string is provided
|
||||
|
@ -983,11 +1219,11 @@ matches_at_help = \state ->
|
|||
## expect Str.walk_utf8_with_index("ABC", [], f) == [65, 66, 67]
|
||||
## ```
|
||||
walk_utf8_with_index : Str, state, (state, U8, U64 -> state) -> state
|
||||
walk_utf8_with_index = \string, state, step ->
|
||||
walk_utf8_with_index = |string, state, step|
|
||||
walk_utf8_with_index_help(string, state, step, 0, Str.count_utf8_bytes(string))
|
||||
|
||||
walk_utf8_with_index_help : Str, state, (state, U8, U64 -> state), U64, U64 -> state
|
||||
walk_utf8_with_index_help = \string, state, step, index, length ->
|
||||
walk_utf8_with_index_help = |string, state, step, index, length|
|
||||
if index < length then
|
||||
byte = Str.get_unsafe(string, index)
|
||||
new_state = step(state, byte, index)
|
||||
|
@ -1008,11 +1244,11 @@ walk_utf8_with_index_help = \string, state, step, index, length ->
|
|||
## expect sum_of_utf8_bytes == 105
|
||||
## ```
|
||||
walk_utf8 : Str, state, (state, U8 -> state) -> state
|
||||
walk_utf8 = \str, initial, step ->
|
||||
walk_utf8 = |str, initial, step|
|
||||
walk_utf8_help(str, initial, step, 0, Str.count_utf8_bytes(str))
|
||||
|
||||
walk_utf8_help : Str, state, (state, U8 -> state), U64, U64 -> state
|
||||
walk_utf8_help = \str, state, step, index, length ->
|
||||
walk_utf8_help = |str, state, step, index, length|
|
||||
if index < length then
|
||||
byte = Str.get_unsafe(str, index)
|
||||
new_state = step(state, byte)
|
||||
|
@ -1031,7 +1267,7 @@ release_excess_capacity : Str -> Str
|
|||
str_to_num : Str -> { berrorcode : U8, aresult : Num * }
|
||||
|
||||
str_to_num_help : Str -> Result (Num a) [InvalidNumStr]
|
||||
str_to_num_help = \string ->
|
||||
str_to_num_help = |string|
|
||||
result : { berrorcode : U8, aresult : Num a }
|
||||
result = str_to_num(string)
|
||||
|
||||
|
@ -1045,7 +1281,7 @@ str_to_num_help = \string ->
|
|||
## expect Str.with_prefix("Awesome", "Roc") == "RocAwesome"
|
||||
## ```
|
||||
with_prefix : Str, Str -> Str
|
||||
with_prefix = \str, prefix -> Str.concat(prefix, str)
|
||||
with_prefix = |str, prefix| Str.concat(prefix, str)
|
||||
|
||||
## Determines whether or not the first Str contains the second.
|
||||
## ```roc
|
||||
|
@ -1054,7 +1290,7 @@ with_prefix = \str, prefix -> Str.concat(prefix, str)
|
|||
## expect Str.contains("anything", "")
|
||||
## ```
|
||||
contains : Str, Str -> Bool
|
||||
contains = \haystack, needle ->
|
||||
contains = |haystack, needle|
|
||||
when first_match(haystack, needle) is
|
||||
Some(_index) -> Bool.true
|
||||
None -> Bool.false
|
||||
|
@ -1067,7 +1303,7 @@ contains = \haystack, needle ->
|
|||
## expect Str.drop_prefix("foobar", "foo") == "bar"
|
||||
## ```
|
||||
drop_prefix : Str, Str -> Str
|
||||
drop_prefix = \haystack, prefix ->
|
||||
drop_prefix = |haystack, prefix|
|
||||
if Str.starts_with(haystack, prefix) then
|
||||
start = Str.count_utf8_bytes(prefix)
|
||||
len = Num.sub_wrap(Str.count_utf8_bytes(haystack), start)
|
||||
|
@ -1084,7 +1320,7 @@ drop_prefix = \haystack, prefix ->
|
|||
## expect Str.drop_suffix("barfoo", "foo") == "bar"
|
||||
## ```
|
||||
drop_suffix : Str, Str -> Str
|
||||
drop_suffix = \haystack, suffix ->
|
||||
drop_suffix = |haystack, suffix|
|
||||
if Str.ends_with(haystack, suffix) then
|
||||
start = 0
|
||||
len = Num.sub_wrap(Str.count_utf8_bytes(haystack), Str.count_utf8_bytes(suffix))
|
||||
|
@ -1092,3 +1328,93 @@ drop_suffix = \haystack, suffix ->
|
|||
substring_unsafe(haystack, start, len)
|
||||
else
|
||||
haystack
|
||||
|
||||
## Returns a version of the string with all [ASCII characters](https://en.wikipedia.org/wiki/ASCII) lowercased.
|
||||
## Non-ASCII characters are left unmodified. For example:
|
||||
##
|
||||
## ```roc
|
||||
## expect Str.with_ascii_lowercased("CAFÉ") == "cafÉ"
|
||||
## ```
|
||||
##
|
||||
## This function is useful for things like [command-line flags](https://en.wikipedia.org/wiki/Command-line_interface#Command-line_option)
|
||||
## and [environment variable names](https://en.wikipedia.org/wiki/Environment_variable)
|
||||
## where you know in advance that you're dealing with a string containing only ASCII characters.
|
||||
## It has better performance than lowercasing operations which take Unicode into account.
|
||||
##
|
||||
## That said, strings received from user input can always contain
|
||||
## non-ASCII Unicode characters, and lowercasing [Unicode](https://unicode.org) works
|
||||
## differently in different languages. For example, the string `"I"` lowercases to `"i"`
|
||||
## in English and to `"ı"` (a [dotless i](https://en.wikipedia.org/wiki/Dotless_I))
|
||||
## in Turkish. These rules can also change in each [Unicode release](https://www.unicode.org/releases/),
|
||||
## so we have separate [`unicode` package](https://github.com/roc-lang/unicode)
|
||||
## for Unicode capitalization that can be upgraded independently from the language's builtins.
|
||||
##
|
||||
## To do a case-insensitive comparison of the ASCII characters in a string,
|
||||
## you can use [Str.caseless_ascii_equals].
|
||||
with_ascii_lowercased : Str -> Str
|
||||
|
||||
expect Str.with_ascii_lowercased("CAFÉ") == "cafÉ"
|
||||
|
||||
## Returns a version of the string with all [ASCII characters](https://en.wikipedia.org/wiki/ASCII) uppercased.
|
||||
## Non-ASCII characters are left unmodified. For example:
|
||||
##
|
||||
## ```roc
|
||||
## expect Str.with_ascii_uppercased("café") == "CAFé"
|
||||
## ```
|
||||
##
|
||||
## This function is useful for things like
|
||||
## [command-line flags](https://en.wikipedia.org/wiki/Command-line_interface#Command-line_option)
|
||||
## and [environment variable names](https://en.wikipedia.org/wiki/Environment_variable)
|
||||
## where you know in advance that you're dealing with a string containing only ASCII characters.
|
||||
## It has better performance than lowercasing operations which take Unicode into account.
|
||||
##
|
||||
## That said, strings received from user input can always contain
|
||||
## non-ASCII Unicode characters, and uppercasing [Unicode](https://unicode.org)
|
||||
## works differently in different languages.
|
||||
## For example, the string `"i"` uppercases to `"I"` in English and to `"İ"`
|
||||
## (a [dotted I](https://en.wikipedia.org/wiki/%C4%B0)) in Turkish.
|
||||
## These rules can also change in each Unicode release,
|
||||
## so we have a separate [`unicode` package](https://github.com/roc-lang/unicode) for Unicode capitalization
|
||||
## that can be upgraded independently from the language's builtins.
|
||||
##
|
||||
## To do a case-insensitive comparison of the ASCII characters in a string,
|
||||
## you can use [Str.caseless_ascii_equals].
|
||||
with_ascii_uppercased : Str -> Str
|
||||
|
||||
expect Str.with_ascii_uppercased("café") == "CAFé"
|
||||
|
||||
## Returns `True` if all the [ASCII characters](https://en.wikipedia.org/wiki/ASCII) in the string are the same
|
||||
## when ignoring differences in capitalization.
|
||||
## Non-ASCII characters must all be exactly the same,
|
||||
## including capitalization. For example:
|
||||
##
|
||||
## ```roc
|
||||
## expect Str.caseless_ascii_equals("café", "CAFé")
|
||||
##
|
||||
## expect !Str.caseless_ascii_equals("café", "CAFÉ")
|
||||
## ```
|
||||
##
|
||||
## The first call returns `True` because all the ASCII characters are the same
|
||||
## when ignoring differences in capitalization, and the only non-ASCII character
|
||||
## (`é`) is the same in both strings. The second call returns `False`because
|
||||
## `é` and `É` are not ASCII characters, and they are different.
|
||||
##
|
||||
## This function is useful for things like [command-line flags](https://en.wikipedia.org/wiki/Command-line_interface#Command-line_option)
|
||||
## and [environment variable names](https://en.wikipedia.org/wiki/Environment_variable)
|
||||
## where you know in advance that you're dealing with a string containing only ASCII characters.
|
||||
## It has better performance than lowercasing operations which take Unicode into account.
|
||||
##
|
||||
## That said, strings received from user input can always contain
|
||||
## non-ASCII Unicode characters, and lowercasing [Unicode](https://unicode.org) works
|
||||
## differently in different languages. For example, the string `"I"` lowercases to `"i"`
|
||||
## in English and to `"ı"` (a [dotless i](https://en.wikipedia.org/wiki/Dotless_I))
|
||||
## in Turkish. These rules can also change in each [Unicode release](https://www.unicode.org/releases/),
|
||||
## so we have separate [`unicode` package](https://github.com/roc-lang/unicode)
|
||||
## for Unicode capitalization that can be upgraded independently from the language's builtins.
|
||||
##
|
||||
## To convert a string's ASCII characters to uppercase or lowercase, you can use [Str.with_ascii_uppercased]
|
||||
## or [Str.with_ascii_lowercased].
|
||||
caseless_ascii_equals : Str, Str -> Bool
|
||||
|
||||
expect Str.caseless_ascii_equals("café", "CAFé")
|
||||
expect !Str.caseless_ascii_equals("café", "CAFÉ")
|
||||
|
|
|
@ -348,6 +348,7 @@ pub const STR_EQUAL: &str = "roc_builtins.str.equal";
|
|||
pub const STR_SUBSTRING_UNSAFE: &str = "roc_builtins.str.substring_unsafe";
|
||||
pub const STR_TO_UTF8: &str = "roc_builtins.str.to_utf8";
|
||||
pub const STR_FROM_UTF8: &str = "roc_builtins.str.from_utf8";
|
||||
pub const STR_FROM_UTF8_LOSSY: &str = "roc_builtins.str.from_utf8_lossy";
|
||||
pub const STR_REPEAT: &str = "roc_builtins.str.repeat";
|
||||
pub const STR_TRIM: &str = "roc_builtins.str.trim";
|
||||
pub const STR_TRIM_START: &str = "roc_builtins.str.trim_start";
|
||||
|
@ -358,6 +359,9 @@ pub const STR_CLONE_TO: &str = "roc_builtins.str.clone_to";
|
|||
pub const STR_WITH_CAPACITY: &str = "roc_builtins.str.with_capacity";
|
||||
pub const STR_ALLOCATION_PTR: &str = "roc_builtins.str.allocation_ptr";
|
||||
pub const STR_RELEASE_EXCESS_CAPACITY: &str = "roc_builtins.str.release_excess_capacity";
|
||||
pub const STR_WITH_ASCII_LOWERCASED: &str = "roc_builtins.str.with_ascii_lowercased";
|
||||
pub const STR_WITH_ASCII_UPPERCASED: &str = "roc_builtins.str.with_ascii_uppercased";
|
||||
pub const STR_CASELESS_ASCII_EQUALS: &str = "roc_builtins.str.caseless_ascii_equals";
|
||||
|
||||
pub const LIST_MAP: &str = "roc_builtins.list.map";
|
||||
pub const LIST_MAP2: &str = "roc_builtins.list.map2";
|
||||
|
|
|
@ -8,6 +8,7 @@ license.workspace = true
|
|||
version.workspace = true
|
||||
|
||||
[dependencies]
|
||||
roc_can_solo.workspace = true
|
||||
roc_collections.workspace = true
|
||||
roc_error_macros.workspace = true
|
||||
roc_exhaustive.workspace = true
|
||||
|
|
|
@ -119,6 +119,7 @@ map_symbol_to_lowlevel_and_arity! {
|
|||
StrSplitOn; STR_SPLIT_ON; 2,
|
||||
StrCountUtf8Bytes; STR_COUNT_UTF8_BYTES; 1,
|
||||
StrFromUtf8; STR_FROM_UTF8_LOWLEVEL; 1,
|
||||
StrFromUtf8Lossy; STR_FROM_UTF8_LOSSY; 1,
|
||||
StrToUtf8; STR_TO_UTF8; 1,
|
||||
StrRepeat; STR_REPEAT; 2,
|
||||
StrTrim; STR_TRIM; 1,
|
||||
|
@ -130,6 +131,9 @@ map_symbol_to_lowlevel_and_arity! {
|
|||
StrToNum; STR_TO_NUM; 1,
|
||||
StrWithCapacity; STR_WITH_CAPACITY; 1,
|
||||
StrReleaseExcessCapacity; STR_RELEASE_EXCESS_CAPACITY; 1,
|
||||
StrWithAsciiLowercased; STR_WITH_ASCII_LOWERCASED; 1,
|
||||
StrWithAsciiUppercased; STR_WITH_ASCII_UPPERCASED; 1,
|
||||
StrCaselessAsciiEquals; STR_CASELESS_ASCII_EQUALS; 2,
|
||||
|
||||
ListLenUsize; LIST_LEN_USIZE; 1,
|
||||
ListLenU64; LIST_LEN_U64; 1,
|
||||
|
@ -212,8 +216,6 @@ map_symbol_to_lowlevel_and_arity! {
|
|||
|
||||
Eq; BOOL_STRUCTURAL_EQ; 2,
|
||||
NotEq; BOOL_STRUCTURAL_NOT_EQ; 2,
|
||||
And; BOOL_AND; 2,
|
||||
Or; BOOL_OR; 2,
|
||||
Not; BOOL_NOT; 1,
|
||||
BoxExpr; BOX_BOX_FUNCTION; 1,
|
||||
UnboxExpr; BOX_UNBOX; 1,
|
||||
|
|
|
@ -915,7 +915,7 @@ pub struct DefTypes {
|
|||
pub loc_symbols: Slice<(Symbol, Region)>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||
pub struct Generalizable(pub bool);
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -11,6 +11,7 @@ use roc_region::all::{LineInfo, Loc, Region};
|
|||
use roc_types::subs::Variable;
|
||||
|
||||
/// The canonicalization environment for a particular module.
|
||||
#[derive(Debug)]
|
||||
pub struct Env<'a> {
|
||||
/// The module's path. Opaques and unqualified references to identifiers
|
||||
/// are assumed to be relative to this path.
|
||||
|
@ -51,6 +52,36 @@ pub struct Env<'a> {
|
|||
}
|
||||
|
||||
impl<'a> Env<'a> {
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn from_solo_can(
|
||||
arena: &'a Bump,
|
||||
module_path: &'a Path,
|
||||
home: ModuleId,
|
||||
dep_idents: &'a IdentIdsByModule,
|
||||
qualified_module_ids: &'a PackageModuleIds<'a>,
|
||||
problems: Vec<Problem>,
|
||||
opt_shorthand: Option<&'a str>,
|
||||
src: &'a str,
|
||||
line_info: &'a mut Option<LineInfo>,
|
||||
) -> Self {
|
||||
Env {
|
||||
arena,
|
||||
src,
|
||||
home,
|
||||
module_path,
|
||||
dep_idents,
|
||||
qualified_module_ids,
|
||||
problems,
|
||||
closures: MutMap::default(),
|
||||
qualified_value_lookups: Default::default(),
|
||||
tailcallable_symbol: None,
|
||||
top_level_symbols: Default::default(),
|
||||
home_params_record: None,
|
||||
opt_shorthand,
|
||||
line_info,
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn new(
|
||||
arena: &'a Bump,
|
||||
|
|
|
@ -1,9 +1,6 @@
|
|||
use std::path::Path;
|
||||
|
||||
use crate::abilities::{AbilitiesStore, ImplKey, PendingAbilitiesStore, ResolvedImpl};
|
||||
use crate::annotation::{canonicalize_annotation, AnnotationFor};
|
||||
use crate::def::{canonicalize_defs, report_unused_imports, Def, DefKind};
|
||||
use crate::desugar::desugar_record_destructures;
|
||||
use crate::env::Env;
|
||||
use crate::expr::{ClosureData, Declarations, ExpectLookup, Expr, Output, PendingDerives};
|
||||
use crate::pattern::{
|
||||
|
@ -16,8 +13,8 @@ use roc_collections::{MutMap, SendMap, VecMap, VecSet};
|
|||
use roc_error_macros::internal_error;
|
||||
use roc_module::ident::Ident;
|
||||
use roc_module::ident::Lowercase;
|
||||
use roc_module::symbol::{IdentId, IdentIds, IdentIdsByModule, ModuleId, PackageModuleIds, Symbol};
|
||||
use roc_parse::ast::{Defs, TypeAnnotation};
|
||||
use roc_module::symbol::{IdentId, ModuleId, Symbol};
|
||||
use roc_parse::ast::{Collection, Defs, Pattern as ParsePattern, TypeAnnotation};
|
||||
use roc_parse::header::HeaderType;
|
||||
use roc_parse::pattern::PatternType;
|
||||
use roc_problem::can::{Problem, RuntimeError};
|
||||
|
@ -209,55 +206,19 @@ fn has_no_implementation(expr: &Expr) -> bool {
|
|||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn canonicalize_module_defs<'a>(
|
||||
arena: &'a Bump,
|
||||
loc_defs: &'a mut Defs<'a>,
|
||||
header_type: &'a roc_parse::header::HeaderType,
|
||||
home: ModuleId,
|
||||
module_path: &'a str,
|
||||
src: &'a str,
|
||||
qualified_module_ids: &'a PackageModuleIds<'a>,
|
||||
exposed_ident_ids: IdentIds,
|
||||
dep_idents: &'a IdentIdsByModule,
|
||||
aliases: MutMap<Symbol, Alias>,
|
||||
imported_abilities_state: PendingAbilitiesStore,
|
||||
initial_scope: MutMap<Ident, (Symbol, Region)>,
|
||||
exposed_symbols: VecSet<Symbol>,
|
||||
symbols_from_requires: &[(Loc<Symbol>, Loc<TypeAnnotation<'a>>)],
|
||||
var_store: &mut VarStore,
|
||||
opt_shorthand: Option<&'a str>,
|
||||
mut scope: Scope,
|
||||
mut env: Env<'a>,
|
||||
loc_defs: Defs<'a>,
|
||||
module_params: Option<(Region, Collection<'a, Loc<ParsePattern<'a>>>)>,
|
||||
) -> ModuleOutput {
|
||||
let mut can_exposed_imports = MutMap::default();
|
||||
|
||||
let mut scope = Scope::new(
|
||||
home,
|
||||
qualified_module_ids
|
||||
.get_name(home)
|
||||
.expect("home module not found")
|
||||
.as_inner()
|
||||
.to_owned(),
|
||||
exposed_ident_ids,
|
||||
imported_abilities_state,
|
||||
);
|
||||
let mut env = Env::new(
|
||||
arena,
|
||||
src,
|
||||
home,
|
||||
arena.alloc(Path::new(module_path)),
|
||||
dep_idents,
|
||||
qualified_module_ids,
|
||||
opt_shorthand,
|
||||
);
|
||||
|
||||
for (name, alias) in aliases.into_iter() {
|
||||
scope.add_alias(
|
||||
name,
|
||||
alias.region,
|
||||
alias.type_variables,
|
||||
alias.infer_ext_in_output_variables,
|
||||
alias.typ,
|
||||
alias.kind,
|
||||
);
|
||||
}
|
||||
|
||||
// Desugar operators (convert them to Apply calls, taking into account
|
||||
// operator precedence and associativity rules), before doing other canonicalization.
|
||||
//
|
||||
|
@ -266,8 +227,6 @@ pub fn canonicalize_module_defs<'a>(
|
|||
// operators, and then again on *their* nested operators, ultimately applying the
|
||||
// rules multiple times unnecessarily.
|
||||
|
||||
crate::desugar::desugar_defs_node_values(&mut env, &mut scope, loc_defs);
|
||||
|
||||
let mut rigid_variables = RigidVariables::default();
|
||||
|
||||
// Initial scope values are treated like defs that appear before any others.
|
||||
|
@ -319,51 +278,42 @@ pub fn canonicalize_module_defs<'a>(
|
|||
|
||||
let mut output = Output::default();
|
||||
|
||||
let module_params = header_type.get_params().as_ref().map(
|
||||
|roc_parse::header::ModuleParams {
|
||||
pattern,
|
||||
before_arrow: _,
|
||||
after_arrow: _,
|
||||
}| {
|
||||
let desugared_patterns =
|
||||
desugar_record_destructures(&mut env, &mut scope, pattern.value);
|
||||
let module_params = module_params.map(|(params_region, desugared_patterns)| {
|
||||
let (destructs, _) = canonicalize_record_destructs(
|
||||
&mut env,
|
||||
var_store,
|
||||
&mut scope,
|
||||
&mut output,
|
||||
PatternType::ModuleParams,
|
||||
&desugared_patterns,
|
||||
params_region,
|
||||
PermitShadows(false),
|
||||
);
|
||||
|
||||
let (destructs, _) = canonicalize_record_destructs(
|
||||
&mut env,
|
||||
var_store,
|
||||
&mut scope,
|
||||
&mut output,
|
||||
PatternType::ModuleParams,
|
||||
&desugared_patterns,
|
||||
pattern.region,
|
||||
PermitShadows(false),
|
||||
);
|
||||
let whole_symbol = scope.gen_unique_symbol();
|
||||
env.top_level_symbols.insert(whole_symbol);
|
||||
|
||||
let whole_symbol = scope.gen_unique_symbol();
|
||||
env.top_level_symbols.insert(whole_symbol);
|
||||
let whole_var = var_store.fresh();
|
||||
|
||||
let whole_var = var_store.fresh();
|
||||
env.home_params_record = Some((whole_symbol, whole_var));
|
||||
|
||||
env.home_params_record = Some((whole_symbol, whole_var));
|
||||
|
||||
ModuleParams {
|
||||
region: pattern.region,
|
||||
whole_var,
|
||||
whole_symbol,
|
||||
record_var: var_store.fresh(),
|
||||
record_ext_var: var_store.fresh(),
|
||||
destructs,
|
||||
arity_by_name: Default::default(),
|
||||
}
|
||||
},
|
||||
);
|
||||
ModuleParams {
|
||||
region: params_region,
|
||||
whole_var,
|
||||
whole_symbol,
|
||||
record_var: var_store.fresh(),
|
||||
record_ext_var: var_store.fresh(),
|
||||
destructs,
|
||||
arity_by_name: Default::default(),
|
||||
}
|
||||
});
|
||||
|
||||
let (defs, output, symbols_introduced, imports_introduced) = canonicalize_defs(
|
||||
&mut env,
|
||||
output,
|
||||
var_store,
|
||||
&mut scope,
|
||||
loc_defs,
|
||||
arena.alloc(loc_defs),
|
||||
PatternType::TopLevelDef,
|
||||
);
|
||||
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
extern crate bumpalo;
|
||||
|
||||
use self::bumpalo::Bump;
|
||||
use roc_can::desugar;
|
||||
use roc_can::env::Env;
|
||||
use roc_can::expr::{canonicalize_expr, Expr};
|
||||
use roc_can::scope::Scope;
|
||||
use roc_can_solo::env::SoloEnv;
|
||||
use roc_can_solo::scope::SoloScope;
|
||||
use roc_collections::all::MutMap;
|
||||
use roc_module::symbol::{IdentIds, Interns, ModuleId, ModuleIds, PackageModuleIds, Symbol};
|
||||
use roc_problem::can::Problem;
|
||||
|
@ -65,7 +66,9 @@ pub fn can_expr_with(arena: &Bump, home: ModuleId, expr_str: &str) -> CanExprOut
|
|||
// visited a BinOp node we'd recursively try to apply this to each of its nested
|
||||
// operators, and then again on *their* nested operators, ultimately applying the
|
||||
// rules multiple times unnecessarily.
|
||||
let loc_expr = desugar::desugar_expr(&mut env, &mut scope, &loc_expr);
|
||||
let mut solo_env = SoloEnv::new(arena, expr_str, Path::new("Test.roc"));
|
||||
let mut solo_scope = SoloScope::new();
|
||||
let loc_expr = roc_can_solo::desugar::desugar_expr(&mut solo_env, &mut solo_scope, &loc_expr);
|
||||
|
||||
scope.add_alias(
|
||||
Symbol::NUM_INT,
|
||||
|
|
|
@ -972,10 +972,10 @@ mod test_can {
|
|||
}
|
||||
|
||||
#[test]
|
||||
fn try_desugar_double_question_suffix() {
|
||||
fn try_desugar_pipe_suffix_pnc() {
|
||||
let src = indoc!(
|
||||
r#"
|
||||
Str.to_u64 "123" ?? Num.max_u64
|
||||
"123" |> Str.to_u64()?
|
||||
"#
|
||||
);
|
||||
let arena = Bump::new();
|
||||
|
@ -985,31 +985,13 @@ mod test_can {
|
|||
|
||||
// Assert that we desugar to:
|
||||
//
|
||||
// when Str.to_u64 "123"
|
||||
// Ok success_BRANCH1_0_9 -> success_BRANCH1_0_9
|
||||
// Err _ -> Num.max_u64
|
||||
// Try(Str.to_u64 "123")
|
||||
|
||||
let (cond_expr, branches) = assert_when(&out.loc_expr.value);
|
||||
let cond_expr = assert_try_expr(&out.loc_expr.value);
|
||||
let cond_args = assert_func_call(cond_expr, "to_u64", CalledVia::Space, &out.interns);
|
||||
|
||||
assert_eq!(cond_args.len(), 1);
|
||||
assert_str_value(&cond_args[0].1.value, "123");
|
||||
assert_eq!(branches.len(), 2);
|
||||
assert_eq!(branches[0].patterns.len(), 1);
|
||||
assert_eq!(branches[1].patterns.len(), 1);
|
||||
assert_pattern_tag_apply_with_ident(
|
||||
&branches[0].patterns[0].pattern.value,
|
||||
"Ok",
|
||||
"success_BRANCH1_0_16",
|
||||
&out.interns,
|
||||
);
|
||||
assert_var_usage(
|
||||
&branches[0].value.value,
|
||||
"success_BRANCH1_0_16",
|
||||
&out.interns,
|
||||
);
|
||||
assert_pattern_tag_apply_with_underscore(&branches[1].patterns[0].pattern.value, "Err");
|
||||
assert_var_usage(&branches[1].value.value, "max_u64", &out.interns);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -1031,7 +1013,7 @@ mod test_can {
|
|||
// when Foo 123 is
|
||||
// Foo try -> try
|
||||
|
||||
let (cond_expr, branches) = assert_when(&out.loc_expr.value);
|
||||
let (cond_expr, branches) = assert_when_expr(&out.loc_expr.value);
|
||||
match cond_expr {
|
||||
Expr::Tag {
|
||||
name, arguments, ..
|
||||
|
@ -1064,6 +1046,169 @@ mod test_can {
|
|||
assert!(&branches[0].guard.is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn desugar_double_question_binop() {
|
||||
let src = indoc!(
|
||||
r#"
|
||||
Str.to_u64("123") ?? Num.max_u64
|
||||
"#
|
||||
);
|
||||
let arena = Bump::new();
|
||||
let out = can_expr_with(&arena, test_home(), src);
|
||||
|
||||
assert_eq!(out.problems, Vec::new());
|
||||
|
||||
// Assert that we desugar to:
|
||||
//
|
||||
// when Str.to_u64("123")
|
||||
// Ok(#double_question_ok_0_17) -> Ok(#double_question_ok_0_17)
|
||||
// Err(_) -> Num.max_u64
|
||||
|
||||
let (cond_expr, branches) = assert_when_expr(&out.loc_expr.value);
|
||||
let cond_args = assert_func_call(cond_expr, "to_u64", CalledVia::Space, &out.interns);
|
||||
|
||||
assert_eq!(cond_args.len(), 1);
|
||||
assert_str_value(&cond_args[0].1.value, "123");
|
||||
|
||||
assert_eq!(branches.len(), 2);
|
||||
assert_eq!(branches[0].patterns.len(), 1);
|
||||
assert_eq!(branches[1].patterns.len(), 1);
|
||||
|
||||
assert_pattern_tag_apply_with_ident(
|
||||
&branches[0].patterns[0].pattern.value,
|
||||
"Ok",
|
||||
"#double_question_ok_0_17",
|
||||
&out.interns,
|
||||
);
|
||||
assert_var_usage(
|
||||
&branches[0].value.value,
|
||||
"#double_question_ok_0_17",
|
||||
&out.interns,
|
||||
);
|
||||
|
||||
assert_pattern_tag_apply_with_underscore(&branches[1].patterns[0].pattern.value, "Err");
|
||||
assert_var_usage(&branches[1].value.value, "max_u64", &out.interns);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn desugar_single_question_binop() {
|
||||
let src = indoc!(
|
||||
r#"
|
||||
Str.to_u64("123") ? FailedToConvert
|
||||
"#
|
||||
);
|
||||
let arena = Bump::new();
|
||||
let out = can_expr_with(&arena, test_home(), src);
|
||||
|
||||
assert_eq!(out.problems, Vec::new());
|
||||
|
||||
// Assert that we desugar to:
|
||||
//
|
||||
// when Str.to_u64("123")
|
||||
// Ok(#single_question_ok_0_17) -> #single_question_ok_0_17
|
||||
// Err(#single_question_err_0_17) -> return Err(FailedToConvert(#single_question_err_0_17))
|
||||
|
||||
let (cond_expr, branches) = assert_when_expr(&out.loc_expr.value);
|
||||
let cond_args = assert_func_call(cond_expr, "to_u64", CalledVia::Space, &out.interns);
|
||||
|
||||
assert_eq!(cond_args.len(), 1);
|
||||
assert_str_value(&cond_args[0].1.value, "123");
|
||||
|
||||
assert_eq!(branches.len(), 2);
|
||||
assert_eq!(branches[0].patterns.len(), 1);
|
||||
assert_eq!(branches[1].patterns.len(), 1);
|
||||
|
||||
assert_pattern_tag_apply_with_ident(
|
||||
&branches[0].patterns[0].pattern.value,
|
||||
"Ok",
|
||||
"#single_question_ok_0_17",
|
||||
&out.interns,
|
||||
);
|
||||
assert_var_usage(
|
||||
&branches[0].value.value,
|
||||
"#single_question_ok_0_17",
|
||||
&out.interns,
|
||||
);
|
||||
|
||||
assert_pattern_tag_apply_with_ident(
|
||||
&branches[1].patterns[0].pattern.value,
|
||||
"Err",
|
||||
"#single_question_err_0_17",
|
||||
&out.interns,
|
||||
);
|
||||
|
||||
let err_expr = assert_return_expr(&branches[1].value.value);
|
||||
let mapped_err = assert_tag_application(err_expr, "Err");
|
||||
assert_eq!(mapped_err.len(), 1);
|
||||
let inner_err = assert_tag_application(&mapped_err[0].1.value, "FailedToConvert");
|
||||
assert_eq!(inner_err.len(), 1);
|
||||
assert_var_usage(
|
||||
&inner_err[0].1.value,
|
||||
"#single_question_err_0_17",
|
||||
&out.interns,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn desugar_and_operator() {
|
||||
let src = indoc!(
|
||||
r#"
|
||||
left = Bool.true
|
||||
right = Bool.false
|
||||
|
||||
left and right
|
||||
"#
|
||||
);
|
||||
let arena = Bump::new();
|
||||
let out = can_expr_with(&arena, test_home(), src);
|
||||
|
||||
assert_eq!(out.problems, Vec::new());
|
||||
|
||||
// Assert that we desugar to:
|
||||
//
|
||||
// if left then right else Bool.false
|
||||
|
||||
let continuation1 = assert_let_expr(&out.loc_expr.value);
|
||||
let continuation2 = assert_let_expr(&continuation1.value);
|
||||
let (branches, final_else) = assert_if_expr(&continuation2.value);
|
||||
|
||||
assert_eq!(branches.len(), 1);
|
||||
|
||||
assert_var_usage(&branches[0].0.value, "left", &out.interns);
|
||||
assert_var_usage(&branches[0].1.value, "right", &out.interns);
|
||||
assert_var_usage(&final_else.value, "false", &out.interns);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn desugar_or_operator() {
|
||||
let src = indoc!(
|
||||
r#"
|
||||
left = Bool.true
|
||||
right = Bool.false
|
||||
|
||||
left or right
|
||||
"#
|
||||
);
|
||||
let arena = Bump::new();
|
||||
let out = can_expr_with(&arena, test_home(), src);
|
||||
|
||||
assert_eq!(out.problems, Vec::new());
|
||||
|
||||
// Assert that we desugar to:
|
||||
//
|
||||
// if left then Bool.true else right
|
||||
|
||||
let continuation1 = assert_let_expr(&out.loc_expr.value);
|
||||
let continuation2 = assert_let_expr(&continuation1.value);
|
||||
let (branches, final_else) = assert_if_expr(&continuation2.value);
|
||||
|
||||
assert_eq!(branches.len(), 1);
|
||||
|
||||
assert_var_usage(&branches[0].0.value, "left", &out.interns);
|
||||
assert_var_usage(&branches[0].1.value, "true", &out.interns);
|
||||
assert_var_usage(&final_else.value, "right", &out.interns);
|
||||
}
|
||||
|
||||
fn assert_num_value(expr: &Expr, num: usize) {
|
||||
match expr {
|
||||
Expr::Num(_, num_str, _, _) => {
|
||||
|
@ -1176,7 +1321,14 @@ mod test_can {
|
|||
}
|
||||
}
|
||||
|
||||
fn assert_when(expr: &Expr) -> (&Expr, &Vec<WhenBranch>) {
|
||||
fn assert_let_expr(expr: &Expr) -> &Loc<Expr> {
|
||||
match expr {
|
||||
Expr::LetNonRec(_, continuation) | Expr::LetRec(_, continuation, _) => continuation,
|
||||
_ => panic!("Expr was not a Let(Non)?Rec: {expr:?}",),
|
||||
}
|
||||
}
|
||||
|
||||
fn assert_when_expr(expr: &Expr) -> (&Expr, &Vec<WhenBranch>) {
|
||||
match expr {
|
||||
Expr::When {
|
||||
loc_cond, branches, ..
|
||||
|
@ -1185,6 +1337,18 @@ mod test_can {
|
|||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::type_complexity)]
|
||||
fn assert_if_expr(expr: &Expr) -> (&[(Loc<Expr>, Loc<Expr>)], &Loc<Expr>) {
|
||||
match expr {
|
||||
Expr::If {
|
||||
branches,
|
||||
final_else,
|
||||
..
|
||||
} => (&branches, &**final_else),
|
||||
_ => panic!("Expr was not a When: {:?}", expr),
|
||||
}
|
||||
}
|
||||
|
||||
fn assert_try_expr(expr: &Expr) -> &Expr {
|
||||
match expr {
|
||||
Expr::Try { result_expr, .. } => &result_expr.value,
|
||||
|
@ -1192,6 +1356,13 @@ mod test_can {
|
|||
}
|
||||
}
|
||||
|
||||
fn assert_return_expr(expr: &Expr) -> &Expr {
|
||||
match expr {
|
||||
Expr::Return { return_value, .. } => &return_value.value,
|
||||
_ => panic!("Expr was not a Return: {:?}", expr),
|
||||
}
|
||||
}
|
||||
|
||||
// TAIL CALLS
|
||||
fn get_closure(expr: &Expr, i: usize) -> roc_can::expr::Recursive {
|
||||
match expr {
|
||||
|
|
|
@ -95,22 +95,6 @@ flags! {
|
|||
/// Prints all type variables entered for fixpoint-fixing.
|
||||
ROC_PRINT_FIXPOINT_FIXING
|
||||
|
||||
/// Verifies that after let-generalization of a def, any rigid variables in the type annotation
|
||||
/// of the def are indeed generalized.
|
||||
///
|
||||
/// Note that rigids need not always be generalized in a def. For example, they may be
|
||||
/// constrained by a type from a lower rank, as `b` is in the following def:
|
||||
///
|
||||
/// F a : { foo : a }
|
||||
/// foo = \arg ->
|
||||
/// x : F b
|
||||
/// x = arg
|
||||
/// x.foo
|
||||
///
|
||||
/// Instead, this flag is useful for checking that in general, introduction is correct, when
|
||||
/// chainging how defs are constrained.
|
||||
ROC_VERIFY_RIGID_LET_GENERALIZED
|
||||
|
||||
/// Verifies that an `occurs` check indeed only contains non-recursive types that need to be
|
||||
/// fixed-up with one new recursion variable.
|
||||
///
|
||||
|
|
|
@ -1206,7 +1206,6 @@ impl<'a> Nodify<'a> for TypeAnnotation<'a> {
|
|||
before: first_node.before,
|
||||
node: Node::CommaSequence {
|
||||
allow_blank_lines: false,
|
||||
allow_newlines: true,
|
||||
indent_rest: false,
|
||||
first: arena.alloc(first_node.node),
|
||||
rest: rest_nodes.into_bump_slice(),
|
||||
|
@ -1313,11 +1312,12 @@ impl<'a> Nodify<'a> for TypeAnnotation<'a> {
|
|||
.to_node(arena, flags)
|
||||
.add_parens(arena, Parens::NotNeeded);
|
||||
|
||||
let mut needs_indent = annot.needs_indent || !annot.after.is_empty();
|
||||
let before = filter_newlines(arena, annot.after);
|
||||
let mut needs_indent = annot.needs_indent || !before.is_empty();
|
||||
|
||||
items.push(Item {
|
||||
comma_before: false,
|
||||
before: annot.after,
|
||||
before,
|
||||
newline: false,
|
||||
space: true,
|
||||
node: Node::Literal(roc_parse::keyword::WHERE),
|
||||
|
@ -1327,7 +1327,8 @@ impl<'a> Nodify<'a> for TypeAnnotation<'a> {
|
|||
|
||||
for (i, clause) in implements_clauses.iter().enumerate() {
|
||||
let node = clause.value.to_node(arena, flags);
|
||||
let before = merge_spaces_conservative(arena, last_after, node.before);
|
||||
let before =
|
||||
filter_newlines(arena, merge_spaces(arena, last_after, node.before));
|
||||
last_after = node.after;
|
||||
items.push(Item {
|
||||
before,
|
||||
|
@ -1346,8 +1347,7 @@ impl<'a> Nodify<'a> for TypeAnnotation<'a> {
|
|||
first: arena.alloc(annot.node),
|
||||
rest: arena.alloc_slice_copy(&items),
|
||||
allow_blank_lines: false,
|
||||
allow_newlines: false,
|
||||
indent_rest: false,
|
||||
indent_rest: true,
|
||||
},
|
||||
after: last_after,
|
||||
needs_indent,
|
||||
|
@ -1358,6 +1358,24 @@ impl<'a> Nodify<'a> for TypeAnnotation<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
fn filter_newlines<'a, 'b: 'a>(
|
||||
arena: &'a Bump,
|
||||
items: &'b [CommentOrNewline<'b>],
|
||||
) -> &'a [CommentOrNewline<'a>] {
|
||||
let count = items.iter().filter(|i| i.is_newline()).count();
|
||||
if count > 0 {
|
||||
let mut new_items = Vec::with_capacity_in(items.len() - count, arena);
|
||||
for item in items {
|
||||
if !item.is_newline() {
|
||||
new_items.push(*item);
|
||||
}
|
||||
}
|
||||
arena.alloc_slice_copy(&new_items)
|
||||
} else {
|
||||
items
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Nodify<'a> for &'a str {
|
||||
fn to_node<'b>(&'a self, arena: &'b Bump, flags: MigrationFlags) -> NodeInfo<'b>
|
||||
where
|
||||
|
@ -1451,7 +1469,6 @@ impl<'a> Nodify<'a> for ImplementsClause<'a> {
|
|||
first: arena.alloc(var.node),
|
||||
rest: arena.alloc_slice_copy(&items),
|
||||
allow_blank_lines: false,
|
||||
allow_newlines: true,
|
||||
indent_rest: false,
|
||||
},
|
||||
after: last_after,
|
||||
|
|
|
@ -1,20 +1,20 @@
|
|||
use crate::annotation::{
|
||||
ann_lift_spaces, ann_lift_spaces_after, is_collection_multiline, ty_is_outdentable,
|
||||
Formattable, Newlines, Parens,
|
||||
ann_lift_spaces_after, is_collection_multiline, Formattable, Newlines, Parens,
|
||||
};
|
||||
use crate::collection::{fmt_collection, Braces};
|
||||
use crate::expr::{
|
||||
expr_lift_and_lower, expr_lift_spaces, expr_lift_spaces_after, expr_lift_spaces_before,
|
||||
fmt_str_literal, is_str_multiline, merge_spaces_conservative, sub_expr_requests_parens,
|
||||
expr_lift_spaces, expr_lift_spaces_after, expr_lift_spaces_before, fmt_str_literal,
|
||||
is_str_multiline, merge_spaces_conservative, sub_expr_requests_parens,
|
||||
};
|
||||
use crate::node::Nodify;
|
||||
use crate::pattern::pattern_lift_spaces_before;
|
||||
use crate::pattern::{pattern_lift_spaces, pattern_lift_spaces_before};
|
||||
use crate::spaces::{
|
||||
fmt_comments_only, fmt_default_newline, fmt_default_spaces, fmt_spaces, NewlineAt, INDENT,
|
||||
};
|
||||
use crate::Buf;
|
||||
use bumpalo::Bump;
|
||||
use roc_error_macros::internal_error;
|
||||
use roc_parse::ast::Spaceable;
|
||||
use roc_parse::ast::{
|
||||
AbilityMember, Defs, Expr, ExtractSpaces, ImportAlias, ImportAsKeyword, ImportExposingKeyword,
|
||||
ImportedModuleName, IngestedFileAnnotation, IngestedFileImport, ModuleImport,
|
||||
|
@ -182,16 +182,29 @@ pub fn valdef_lift_spaces<'a, 'b: 'a>(
|
|||
}
|
||||
}
|
||||
ValueDef::Body(pat, expr) => {
|
||||
let pat_lifted = pattern_lift_spaces_before(arena, &pat.value);
|
||||
let expr_lifted = expr_lift_spaces_after(Parens::NotNeeded, arena, &expr.value);
|
||||
let pat_lifted = pattern_lift_spaces(arena, &pat.value);
|
||||
|
||||
Spaces {
|
||||
before: pat_lifted.before,
|
||||
item: ValueDef::Body(
|
||||
arena.alloc(Loc::at(pat.region, pat_lifted.item)),
|
||||
arena.alloc(Loc::at(expr.region, expr_lifted.item)),
|
||||
),
|
||||
after: expr_lifted.after,
|
||||
// Don't format the `{} =` for defs with this pattern
|
||||
if is_body_unit_assignment(&pat_lifted, &expr.extract_spaces()) {
|
||||
let lifted = expr_lift_spaces(Parens::NotNeeded, arena, &expr.value);
|
||||
Spaces {
|
||||
before: lifted.before,
|
||||
item: ValueDef::Stmt(arena.alloc(Loc::at_zero(lifted.item))),
|
||||
after: lifted.after,
|
||||
}
|
||||
} else {
|
||||
let lifted = expr_lift_spaces(Parens::NotNeeded, arena, &expr.value);
|
||||
Spaces {
|
||||
before: pat_lifted.before,
|
||||
item: ValueDef::Body(
|
||||
arena.alloc(Loc::at(
|
||||
pat.region,
|
||||
pat_lifted.item.maybe_after(arena, pat_lifted.after),
|
||||
)),
|
||||
expr,
|
||||
),
|
||||
after: lifted.after,
|
||||
}
|
||||
}
|
||||
}
|
||||
ValueDef::AnnotatedBody {
|
||||
|
@ -312,11 +325,26 @@ pub fn valdef_lift_spaces_before<'a, 'b: 'a>(
|
|||
}
|
||||
}
|
||||
ValueDef::Body(pat, expr) => {
|
||||
let pat_lifted = pattern_lift_spaces_before(arena, &pat.value);
|
||||
let pat_lifted = pattern_lift_spaces(arena, &pat.value);
|
||||
|
||||
SpacesBefore {
|
||||
before: pat_lifted.before,
|
||||
item: ValueDef::Body(arena.alloc(Loc::at(pat.region, pat_lifted.item)), expr),
|
||||
// Don't format the `{} =` for defs with this pattern
|
||||
if is_body_unit_assignment(&pat_lifted, &expr.extract_spaces()) {
|
||||
let lifted = expr_lift_spaces_before(Parens::NotNeeded, arena, &expr.value);
|
||||
SpacesBefore {
|
||||
before: lifted.before,
|
||||
item: ValueDef::Stmt(arena.alloc(Loc::at_zero(lifted.item))),
|
||||
}
|
||||
} else {
|
||||
SpacesBefore {
|
||||
before: pat_lifted.before,
|
||||
item: ValueDef::Body(
|
||||
arena.alloc(Loc::at(
|
||||
pat.region,
|
||||
pat_lifted.item.maybe_after(arena, pat_lifted.after),
|
||||
)),
|
||||
expr,
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
ValueDef::AnnotatedBody {
|
||||
|
@ -396,6 +424,20 @@ pub fn valdef_lift_spaces_before<'a, 'b: 'a>(
|
|||
}
|
||||
}
|
||||
|
||||
fn is_body_unit_assignment(pat: &Spaces<'_, Pattern<'_>>, body: &Spaces<'_, Expr<'_>>) -> bool {
|
||||
if let Pattern::RecordDestructure(collection) = pat.item {
|
||||
collection.is_empty()
|
||||
&& pat.before.iter().all(|s| s.is_newline())
|
||||
&& pat.after.iter().all(|s| s.is_newline())
|
||||
&& !matches!(body.item, Expr::Defs(..))
|
||||
&& !matches!(body.item, Expr::Return(..))
|
||||
&& !matches!(body.item, Expr::DbgStmt { .. })
|
||||
&& !starts_with_expect_ident(&body.item)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Formattable for TypeDef<'a> {
|
||||
fn is_multiline(&self) -> bool {
|
||||
use roc_parse::ast::TypeDef::*;
|
||||
|
@ -412,22 +454,15 @@ impl<'a> Formattable for TypeDef<'a> {
|
|||
|
||||
match self {
|
||||
Alias { header, ann } => {
|
||||
header.format(buf, indent);
|
||||
|
||||
buf.indent(indent);
|
||||
buf.push_str(" :");
|
||||
buf.spaces(1);
|
||||
|
||||
let ann = ann_lift_spaces(buf.text.bump(), &ann.value);
|
||||
|
||||
let inner_indent = if ty_is_outdentable(&ann.item) {
|
||||
indent
|
||||
} else {
|
||||
indent + INDENT
|
||||
};
|
||||
fmt_comments_only(buf, ann.before.iter(), NewlineAt::Bottom, inner_indent);
|
||||
ann.item.format(buf, inner_indent);
|
||||
fmt_spaces(buf, ann.after.iter(), indent);
|
||||
fmt_general_def(
|
||||
header,
|
||||
Parens::NotNeeded,
|
||||
buf,
|
||||
indent,
|
||||
":",
|
||||
&ann.value,
|
||||
newlines,
|
||||
);
|
||||
}
|
||||
Opaque {
|
||||
header,
|
||||
|
@ -797,7 +832,7 @@ impl<'a> Formattable for ValueDef<'a> {
|
|||
);
|
||||
}
|
||||
Body(loc_pattern, loc_expr) => {
|
||||
fmt_body(buf, true, &loc_pattern.value, &loc_expr.value, indent);
|
||||
fmt_body(buf, &loc_pattern.value, &loc_expr.value, indent);
|
||||
}
|
||||
Dbg { condition, .. } => fmt_dbg_in_def(buf, condition, self.is_multiline(), indent),
|
||||
Expect { condition, .. } => fmt_expect(buf, condition, self.is_multiline(), indent),
|
||||
|
@ -826,7 +861,7 @@ impl<'a> Formattable for ValueDef<'a> {
|
|||
fmt_annotated_body_comment(buf, indent, lines_between);
|
||||
|
||||
buf.newline();
|
||||
fmt_body(buf, false, &body_pattern.value, &body_expr.value, indent);
|
||||
fmt_body(buf, &body_pattern.value, &body_expr.value, indent);
|
||||
}
|
||||
ModuleImport(module_import) => module_import.format(buf, indent),
|
||||
IngestedFileImport(ingested_file_import) => ingested_file_import.format(buf, indent),
|
||||
|
@ -957,34 +992,7 @@ pub fn fmt_annotated_body_comment<'a>(
|
|||
}
|
||||
}
|
||||
|
||||
pub fn fmt_body<'a>(
|
||||
buf: &mut Buf,
|
||||
allow_simplify_empty_record_destructure: bool,
|
||||
pattern: &'a Pattern<'a>,
|
||||
body: &'a Expr<'a>,
|
||||
indent: u16,
|
||||
) {
|
||||
let pattern_extracted = pattern.extract_spaces();
|
||||
// Check if this is an assignment into the unit value
|
||||
let is_unit_assignment = if let Pattern::RecordDestructure(collection) = pattern_extracted.item
|
||||
{
|
||||
allow_simplify_empty_record_destructure
|
||||
&& collection.is_empty()
|
||||
&& pattern_extracted.before.iter().all(|s| s.is_newline())
|
||||
&& pattern_extracted.after.iter().all(|s| s.is_newline())
|
||||
&& !matches!(body.extract_spaces().item, Expr::Defs(..))
|
||||
&& !matches!(body.extract_spaces().item, Expr::Return(..))
|
||||
&& !matches!(body.extract_spaces().item, Expr::DbgStmt { .. })
|
||||
&& !starts_with_expect_ident(body)
|
||||
} else {
|
||||
false
|
||||
};
|
||||
|
||||
// Don't format the `{} =` for defs with this pattern
|
||||
if is_unit_assignment {
|
||||
return body.format_with_options(buf, Parens::NotNeeded, Newlines::No, indent);
|
||||
}
|
||||
|
||||
pub fn fmt_body<'a>(buf: &mut Buf, pattern: &'a Pattern<'a>, body: &'a Expr<'a>, indent: u16) {
|
||||
pattern.format_with_options(buf, Parens::InApply, Newlines::No, indent);
|
||||
|
||||
if pattern.is_multiline() {
|
||||
|
@ -996,7 +1004,12 @@ pub fn fmt_body<'a>(
|
|||
let indent = buf.cur_line_indent();
|
||||
buf.push_str("=");
|
||||
|
||||
let body = expr_lift_and_lower(Parens::NotNeeded, buf.text.bump(), body);
|
||||
let body_lifted = expr_lift_spaces(Parens::NotNeeded, buf.text.bump(), body);
|
||||
|
||||
let after = body_lifted.after;
|
||||
let body = body_lifted
|
||||
.item
|
||||
.maybe_before(buf.text.bump(), body_lifted.before);
|
||||
|
||||
if body.is_multiline() {
|
||||
match body {
|
||||
|
@ -1009,10 +1022,7 @@ pub fn fmt_body<'a>(
|
|||
_ => false,
|
||||
};
|
||||
|
||||
if is_unit_assignment {
|
||||
fmt_comments_only(buf, spaces.iter(), NewlineAt::Bottom, indent);
|
||||
sub_def.format_with_options(buf, Parens::NotNeeded, Newlines::Yes, indent);
|
||||
} else if should_outdent {
|
||||
if should_outdent {
|
||||
buf.spaces(1);
|
||||
sub_def.format_with_options(buf, Parens::NotNeeded, Newlines::Yes, indent);
|
||||
} else {
|
||||
|
@ -1057,7 +1067,7 @@ pub fn fmt_body<'a>(
|
|||
buf.ensure_ends_with_newline();
|
||||
body.format_with_options(buf, Parens::NotNeeded, Newlines::Yes, indent + INDENT);
|
||||
}
|
||||
Expr::Defs(..) | Expr::BinOps(_, _) => {
|
||||
Expr::Defs(..) | Expr::BinOps(..) => {
|
||||
// Binop chains always get a newline. Otherwise you can have things like:
|
||||
//
|
||||
// something = foo
|
||||
|
@ -1092,6 +1102,8 @@ pub fn fmt_body<'a>(
|
|||
buf.spaces(1);
|
||||
body.format_with_options(buf, Parens::NotNeeded, Newlines::Yes, indent);
|
||||
}
|
||||
|
||||
fmt_spaces(buf, after.iter(), indent);
|
||||
}
|
||||
|
||||
fn starts_with_expect_ident(expr: &Expr<'_>) -> bool {
|
||||
|
@ -1116,6 +1128,7 @@ pub fn starts_with_block_string_literal(expr: &Expr<'_>) -> bool {
|
|||
}
|
||||
Expr::Apply(inner, _, _) => starts_with_block_string_literal(&inner.value),
|
||||
Expr::RecordAccess(inner, _) => starts_with_block_string_literal(inner),
|
||||
Expr::TupleAccess(inner, _) => starts_with_block_string_literal(inner),
|
||||
Expr::PncApply(inner, _) => starts_with_block_string_literal(&inner.value),
|
||||
Expr::TrySuffix(inner) => starts_with_block_string_literal(inner),
|
||||
_ => false,
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use crate::annotation::{except_last, is_collection_multiline, Formattable, Newlines, Parens};
|
||||
use crate::collection::{fmt_collection, Braces};
|
||||
use crate::def::{fmt_defs, valdef_lift_spaces_before};
|
||||
use crate::def::{fmt_defs, starts_with_block_string_literal, valdef_lift_spaces_before};
|
||||
use crate::node::Prec;
|
||||
use crate::pattern::{
|
||||
fmt_pattern, pattern_lift_spaces, snakify_camel_ident, starts_with_inline_comment,
|
||||
|
@ -233,16 +233,9 @@ fn format_expr_only(
|
|||
Expr::If {
|
||||
if_thens: branches,
|
||||
final_else,
|
||||
indented_else,
|
||||
indented_else: _,
|
||||
} => {
|
||||
fmt_if(
|
||||
buf,
|
||||
branches,
|
||||
final_else,
|
||||
item.is_multiline(),
|
||||
*indented_else,
|
||||
indent,
|
||||
);
|
||||
fmt_if(buf, branches, final_else, item.is_multiline(), indent);
|
||||
}
|
||||
Expr::When(loc_condition, branches) => fmt_when(buf, loc_condition, branches, indent),
|
||||
Expr::Tuple(items) => fmt_expr_collection(buf, indent, Braces::Round, *items, Newlines::No),
|
||||
|
@ -264,7 +257,7 @@ fn format_expr_only(
|
|||
let before_all_newlines = lifted.before.iter().all(|s| s.is_newline());
|
||||
|
||||
let needs_newline =
|
||||
!before_all_newlines || term_starts_with_multiline_str(&lifted.item);
|
||||
!before_all_newlines || starts_with_block_string_literal(&lifted.item);
|
||||
|
||||
let needs_parens = (needs_newline
|
||||
&& matches!(unary_op.value, called_via::UnaryOp::Negate))
|
||||
|
@ -367,14 +360,6 @@ fn format_expr_only(
|
|||
}
|
||||
}
|
||||
|
||||
fn term_starts_with_multiline_str(expr: &Expr<'_>) -> bool {
|
||||
match expr {
|
||||
Expr::Str(text) => is_str_multiline(text),
|
||||
Expr::PncApply(inner, _) => term_starts_with_multiline_str(&inner.value),
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
fn prepare_expr_field_collection<'a>(
|
||||
arena: &'a Bump,
|
||||
items: Collection<'a, Loc<AssignedField<'a, Expr<'a>>>>,
|
||||
|
@ -959,10 +944,11 @@ fn push_op(buf: &mut Buf, op: BinOp) {
|
|||
called_via::BinOp::GreaterThan => buf.push('>'),
|
||||
called_via::BinOp::LessThanOrEq => buf.push_str("<="),
|
||||
called_via::BinOp::GreaterThanOrEq => buf.push_str(">="),
|
||||
called_via::BinOp::And => buf.push_str("&&"),
|
||||
called_via::BinOp::Or => buf.push_str("||"),
|
||||
called_via::BinOp::Or => buf.push_str("or"),
|
||||
called_via::BinOp::And => buf.push_str("and"),
|
||||
called_via::BinOp::Pizza => buf.push_str("|>"),
|
||||
called_via::BinOp::DoubleQuestion => buf.push_str("??"),
|
||||
called_via::BinOp::SingleQuestion => buf.push_str("?"),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1025,14 +1011,6 @@ pub fn fmt_str_literal(buf: &mut Buf, literal: StrLiteral, indent: u16) {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn expr_lift_and_lower<'a, 'b: 'a>(
|
||||
_parens: Parens,
|
||||
arena: &'a Bump,
|
||||
expr: &Expr<'b>,
|
||||
) -> Expr<'a> {
|
||||
lower(arena, expr_lift_spaces(Parens::NotNeeded, arena, expr))
|
||||
}
|
||||
|
||||
pub fn expr_lift_spaces<'a, 'b: 'a>(
|
||||
parens: Parens,
|
||||
arena: &'a Bump,
|
||||
|
@ -1495,7 +1473,6 @@ fn fmt_binops<'a>(
|
|||
buf: &mut Buf,
|
||||
lefts: &'a [(Loc<Expr<'a>>, Loc<BinOp>)],
|
||||
loc_right_side: &'a Loc<Expr<'a>>,
|
||||
|
||||
indent: u16,
|
||||
) {
|
||||
let is_multiline = loc_right_side.value.is_multiline()
|
||||
|
@ -1824,6 +1801,8 @@ fn guard_needs_parens(value: &Expr<'_>) -> bool {
|
|||
Expr::ParensAround(expr) | Expr::SpaceBefore(expr, _) | Expr::SpaceAfter(expr, _) => {
|
||||
guard_needs_parens(expr)
|
||||
}
|
||||
Expr::BinOps(_lefts, right) => guard_needs_parens(&right.value),
|
||||
Expr::UnaryOp(inner, _) => guard_needs_parens(&inner.value),
|
||||
Expr::Closure(_, body) => guard_needs_parens(&body.value),
|
||||
Expr::Defs(_, final_expr) => guard_needs_parens(&final_expr.value),
|
||||
_ => false,
|
||||
|
@ -1941,8 +1920,6 @@ fn fmt_if<'a>(
|
|||
branches: &'a [(Loc<Expr<'a>>, Loc<Expr<'a>>)],
|
||||
final_else: &'a Loc<Expr<'a>>,
|
||||
is_multiline: bool,
|
||||
indented_else: bool,
|
||||
|
||||
indent: u16,
|
||||
) {
|
||||
// let is_multiline_then = loc_then.is_multiline();
|
||||
|
@ -1986,35 +1963,26 @@ fn fmt_if<'a>(
|
|||
}
|
||||
|
||||
buf.ensure_ends_with_whitespace();
|
||||
if indented_else {
|
||||
buf.indent(indent + INDENT);
|
||||
buf.push_str("else");
|
||||
buf.newline();
|
||||
buf.newline();
|
||||
} else if is_multiline {
|
||||
buf.indent(indent);
|
||||
buf.push_str("else");
|
||||
buf.indent(indent);
|
||||
buf.push_str("else");
|
||||
if is_multiline {
|
||||
buf.newline();
|
||||
} else {
|
||||
buf.indent(indent);
|
||||
buf.push_str("else");
|
||||
buf.spaces(1);
|
||||
}
|
||||
let indent = if indented_else { indent } else { return_indent };
|
||||
final_else.format(buf, indent);
|
||||
final_else.format(buf, return_indent);
|
||||
}
|
||||
|
||||
fn fmt_closure<'a>(
|
||||
buf: &mut Buf,
|
||||
loc_patterns: &'a [Loc<Pattern<'a>>],
|
||||
loc_ret: &'a Loc<Expr<'a>>,
|
||||
|
||||
indent: u16,
|
||||
) {
|
||||
use self::Expr::*;
|
||||
|
||||
buf.indent(indent);
|
||||
buf.push('\\');
|
||||
buf.push('|');
|
||||
|
||||
let arguments_are_multiline = loc_patterns
|
||||
.iter()
|
||||
|
@ -2062,12 +2030,10 @@ fn fmt_closure<'a>(
|
|||
if arguments_are_multiline {
|
||||
buf.ensure_ends_with_newline();
|
||||
buf.indent(indent);
|
||||
} else {
|
||||
buf.spaces(1);
|
||||
}
|
||||
|
||||
let arrow_line_indent = buf.cur_line_indent();
|
||||
buf.push_str("->");
|
||||
buf.push_str("|");
|
||||
buf.spaces(1);
|
||||
|
||||
let is_multiline = loc_ret.value.is_multiline();
|
||||
|
@ -2284,7 +2250,8 @@ pub fn sub_expr_requests_parens(expr: &Expr<'_>) -> bool {
|
|||
| BinOp::And
|
||||
| BinOp::Or
|
||||
| BinOp::Pizza
|
||||
| BinOp::DoubleQuestion => true,
|
||||
| BinOp::DoubleQuestion
|
||||
| BinOp::SingleQuestion => true,
|
||||
})
|
||||
}
|
||||
Expr::If { .. } => true,
|
||||
|
|
|
@ -5,7 +5,7 @@ use crate::{
|
|||
annotation::{Formattable, Newlines, Parens},
|
||||
collection::Braces,
|
||||
expr::merge_spaces_conservative,
|
||||
spaces::{fmt_comments_only, fmt_spaces, fmt_spaces_no_blank_lines, NewlineAt, INDENT},
|
||||
spaces::{fmt_spaces, fmt_spaces_no_blank_lines, INDENT},
|
||||
Buf, MigrationFlags,
|
||||
};
|
||||
|
||||
|
@ -87,7 +87,6 @@ pub enum Node<'a> {
|
|||
},
|
||||
CommaSequence {
|
||||
allow_blank_lines: bool,
|
||||
allow_newlines: bool,
|
||||
indent_rest: bool,
|
||||
first: &'a Node<'a>,
|
||||
rest: &'a [Item<'a>],
|
||||
|
@ -124,12 +123,8 @@ pub struct Item<'a> {
|
|||
}
|
||||
|
||||
impl<'a> Item<'a> {
|
||||
fn is_multiline(&self, allow_newlines: bool) -> bool {
|
||||
let has_newlines = if allow_newlines {
|
||||
!self.before.is_empty()
|
||||
} else {
|
||||
self.before.iter().any(|c| c.is_comment())
|
||||
};
|
||||
fn is_multiline(&self) -> bool {
|
||||
let has_newlines = !self.before.is_empty();
|
||||
self.newline || has_newlines || self.node.is_multiline()
|
||||
}
|
||||
}
|
||||
|
@ -273,7 +268,6 @@ impl<'b> NodeInfo<'b> {
|
|||
},
|
||||
node: Node::CommaSequence {
|
||||
allow_blank_lines: false,
|
||||
allow_newlines: true,
|
||||
indent_rest,
|
||||
first: arena.alloc(first.node),
|
||||
rest: rest.into_bump_slice(),
|
||||
|
@ -361,11 +355,10 @@ impl<'a> Formattable for Node<'a> {
|
|||
} => after.is_multiline() || items.iter().any(|item| item.is_multiline()),
|
||||
Node::CommaSequence {
|
||||
allow_blank_lines: _,
|
||||
allow_newlines,
|
||||
indent_rest: _,
|
||||
first,
|
||||
rest,
|
||||
} => first.is_multiline() || rest.iter().any(|item| item.is_multiline(*allow_newlines)),
|
||||
} => first.is_multiline() || rest.iter().any(|item| item.is_multiline()),
|
||||
Node::Literal(_) => false,
|
||||
Node::TypeAnnotation(type_annotation) => type_annotation.is_multiline(),
|
||||
Node::Pattern(pat) => pat.is_multiline(),
|
||||
|
@ -429,7 +422,6 @@ impl<'a> Formattable for Node<'a> {
|
|||
}
|
||||
Node::CommaSequence {
|
||||
allow_blank_lines,
|
||||
allow_newlines,
|
||||
indent_rest,
|
||||
first,
|
||||
rest,
|
||||
|
@ -448,10 +440,8 @@ impl<'a> Formattable for Node<'a> {
|
|||
}
|
||||
if *allow_blank_lines {
|
||||
fmt_spaces(buf, item.before.iter(), indent);
|
||||
} else if *allow_newlines {
|
||||
fmt_spaces_no_blank_lines(buf, item.before.iter(), inner_indent);
|
||||
} else {
|
||||
fmt_comments_only(buf, item.before.iter(), NewlineAt::Bottom, inner_indent);
|
||||
fmt_spaces_no_blank_lines(buf, item.before.iter(), inner_indent);
|
||||
}
|
||||
if item.newline {
|
||||
buf.ensure_ends_with_newline();
|
||||
|
|
|
@ -294,7 +294,8 @@ fn fmt_pattern_only(
|
|||
is_negative,
|
||||
} => {
|
||||
buf.indent(indent);
|
||||
let needs_parens = parens == Parens::InClosurePattern;
|
||||
let needs_parens = parens == Parens::InClosurePattern
|
||||
|| (parens == Parens::InPncApplyFunc && *is_negative);
|
||||
if needs_parens {
|
||||
buf.push('(');
|
||||
}
|
||||
|
@ -317,7 +318,8 @@ fn fmt_pattern_only(
|
|||
}
|
||||
Pattern::FloatLiteral(string) => {
|
||||
buf.indent(indent);
|
||||
let needs_parens = parens == Parens::InClosurePattern;
|
||||
let needs_parens = parens == Parens::InClosurePattern
|
||||
|| (parens == Parens::InPncApplyFunc && string.starts_with('-'));
|
||||
if needs_parens {
|
||||
buf.push('(');
|
||||
}
|
||||
|
|
|
@ -1268,20 +1268,6 @@ trait Backend<'a> {
|
|||
internal_error!("bitwise xor on a non-integer")
|
||||
}
|
||||
}
|
||||
LowLevel::And => {
|
||||
if let LayoutRepr::Builtin(Builtin::Bool) = self.interner().get_repr(*ret_layout) {
|
||||
self.build_int_bitwise_and(sym, &args[0], &args[1], IntWidth::U8)
|
||||
} else {
|
||||
internal_error!("bitwise and on a non-integer")
|
||||
}
|
||||
}
|
||||
LowLevel::Or => {
|
||||
if let LayoutRepr::Builtin(Builtin::Bool) = self.interner().get_repr(*ret_layout) {
|
||||
self.build_int_bitwise_or(sym, &args[0], &args[1], IntWidth::U8)
|
||||
} else {
|
||||
internal_error!("bitwise or on a non-integer")
|
||||
}
|
||||
}
|
||||
LowLevel::NumShiftLeftBy => {
|
||||
if let LayoutRepr::Builtin(Builtin::Int(int_width)) =
|
||||
self.interner().get_repr(*ret_layout)
|
||||
|
@ -1677,6 +1663,13 @@ trait Backend<'a> {
|
|||
ret_layout,
|
||||
)
|
||||
}
|
||||
LowLevel::StrFromUtf8Lossy => self.build_fn_call(
|
||||
sym,
|
||||
bitcode::STR_FROM_UTF8_LOSSY.to_string(),
|
||||
args,
|
||||
arg_layouts,
|
||||
ret_layout,
|
||||
),
|
||||
LowLevel::StrRepeat => self.build_fn_call(
|
||||
sym,
|
||||
bitcode::STR_REPEAT.to_string(),
|
||||
|
@ -1726,6 +1719,27 @@ trait Backend<'a> {
|
|||
arg_layouts,
|
||||
ret_layout,
|
||||
),
|
||||
LowLevel::StrWithAsciiLowercased => self.build_fn_call(
|
||||
sym,
|
||||
bitcode::STR_WITH_ASCII_LOWERCASED.to_string(),
|
||||
args,
|
||||
arg_layouts,
|
||||
ret_layout,
|
||||
),
|
||||
LowLevel::StrWithAsciiUppercased => self.build_fn_call(
|
||||
sym,
|
||||
bitcode::STR_WITH_ASCII_UPPERCASED.to_string(),
|
||||
args,
|
||||
arg_layouts,
|
||||
ret_layout,
|
||||
),
|
||||
LowLevel::StrCaselessAsciiEquals => self.build_fn_call(
|
||||
sym,
|
||||
bitcode::STR_CASELESS_ASCII_EQUALS.to_string(),
|
||||
args,
|
||||
arg_layouts,
|
||||
ret_layout,
|
||||
),
|
||||
LowLevel::StrToNum => {
|
||||
let number_layout = match self.interner().get_repr(*ret_layout) {
|
||||
LayoutRepr::Struct(field_layouts) => field_layouts[0], // TODO: why is it sometimes a struct?
|
||||
|
|
|
@ -7,7 +7,6 @@ use inkwell::values::{BasicValueEnum, FunctionValue, IntValue, PointerValue, Str
|
|||
use inkwell::{AddressSpace, IntPredicate};
|
||||
use morphic_lib::UpdateMode;
|
||||
use roc_builtins::bitcode;
|
||||
use roc_module::symbol::Symbol;
|
||||
use roc_mono::layout::{
|
||||
Builtin, InLayout, Layout, LayoutIds, LayoutInterner, LayoutRepr, STLayoutInterner,
|
||||
};
|
||||
|
@ -17,7 +16,6 @@ use super::build::{
|
|||
create_entry_block_alloca, load_roc_value, store_roc_value, use_roc_value, BuilderExt,
|
||||
};
|
||||
use super::convert::zig_list_type;
|
||||
use super::scope::Scope;
|
||||
use super::struct_::struct_from_fields;
|
||||
|
||||
fn call_list_bitcode_fn_1<'ctx>(
|
||||
|
@ -29,20 +27,6 @@ fn call_list_bitcode_fn_1<'ctx>(
|
|||
call_list_bitcode_fn(env, &[list], other_arguments, BitcodeReturns::List, fn_name)
|
||||
}
|
||||
|
||||
pub(crate) fn list_symbol_to_c_abi<'a, 'ctx>(
|
||||
env: &Env<'a, 'ctx, '_>,
|
||||
scope: &Scope<'a, 'ctx>,
|
||||
symbol: Symbol,
|
||||
) -> PointerValue<'ctx> {
|
||||
let list_type = zig_list_type(env);
|
||||
let list_alloca = create_entry_block_alloca(env, list_type, "list_alloca");
|
||||
|
||||
let list = scope.load_symbol(&symbol);
|
||||
env.builder.new_build_store(list_alloca, list);
|
||||
|
||||
list_alloca
|
||||
}
|
||||
|
||||
pub(crate) fn pass_update_mode<'ctx>(
|
||||
env: &Env<'_, 'ctx, '_>,
|
||||
update_mode: UpdateMode,
|
||||
|
|
|
@ -1,30 +1,68 @@
|
|||
use crate::llvm::build::Env;
|
||||
use inkwell::values::{BasicValueEnum, PointerValue};
|
||||
use roc_builtins::bitcode;
|
||||
use roc_mono::layout::{InLayout, Layout, LayoutRepr, STLayoutInterner};
|
||||
|
||||
use super::bitcode::{call_str_bitcode_fn, BitcodeReturns};
|
||||
use super::build::load_roc_value;
|
||||
use super::bitcode::{
|
||||
call_str_bitcode_fn, call_void_bitcode_fn, pass_list_or_string_to_zig_32bit,
|
||||
pass_list_to_zig_64bit, pass_list_to_zig_wasm, BitcodeReturns,
|
||||
};
|
||||
use super::build::{create_entry_block_alloca, load_roc_value, Env};
|
||||
use bumpalo::collections::Vec;
|
||||
|
||||
pub static CHAR_LAYOUT: InLayout = Layout::U8;
|
||||
|
||||
pub(crate) fn decode_from_utf8_result<'a, 'ctx>(
|
||||
pub(crate) fn call_str_from_utf_bitcode_fn<'a, 'ctx>(
|
||||
env: &Env<'a, 'ctx, '_>,
|
||||
layout_interner: &STLayoutInterner<'a>,
|
||||
pointer: PointerValue<'ctx>,
|
||||
args: &[BasicValueEnum<'ctx>],
|
||||
result_struct_name: &str,
|
||||
fn_name: &str,
|
||||
) -> BasicValueEnum<'ctx> {
|
||||
let result_type = env.module.get_struct_type(result_struct_name).unwrap();
|
||||
let result_ptr = create_entry_block_alloca(env, result_type, "alloca_from_utf_result");
|
||||
// FromUtf8Result, FromUtf16Result, FromUtf32Result all have the same layout of
|
||||
// - index: u64
|
||||
// - string: RocStr
|
||||
// - is_ok: bool
|
||||
// - problem_code: u8
|
||||
let layout =
|
||||
LayoutRepr::Struct(
|
||||
env.arena
|
||||
.alloc([Layout::U64, Layout::STR, Layout::BOOL, Layout::U8]),
|
||||
);
|
||||
|
||||
let list = args[0];
|
||||
let argn = &args[1..];
|
||||
let mut args: Vec<BasicValueEnum<'ctx>> = Vec::with_capacity_in(args.len() + 2, env.arena);
|
||||
args.push(result_ptr.into());
|
||||
|
||||
use roc_target::Architecture::*;
|
||||
match env.target.architecture() {
|
||||
Aarch32 | X86_32 => {
|
||||
let (a, b) = pass_list_or_string_to_zig_32bit(env, list.into_struct_value());
|
||||
args.push(a.into());
|
||||
args.push(b.into());
|
||||
}
|
||||
Aarch64 | X86_64 => {
|
||||
let list = pass_list_to_zig_64bit(env, list);
|
||||
args.push(list.into());
|
||||
}
|
||||
Wasm32 => {
|
||||
let list = pass_list_to_zig_wasm(env, list);
|
||||
args.push(list.into());
|
||||
}
|
||||
};
|
||||
|
||||
args.extend(argn);
|
||||
|
||||
call_void_bitcode_fn(env, &args, fn_name);
|
||||
|
||||
load_roc_value(
|
||||
env,
|
||||
layout_interner,
|
||||
layout,
|
||||
pointer,
|
||||
"load_decode_from_utf8_result",
|
||||
result_ptr,
|
||||
"load_from_utf_result",
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -37,9 +37,9 @@ use crate::llvm::{
|
|||
build_list::{
|
||||
list_append_unsafe, list_clone, list_concat, list_drop_at, list_get_unsafe, list_len_usize,
|
||||
list_prepend, list_release_excess_capacity, list_replace_unsafe, list_reserve,
|
||||
list_sort_with, list_sublist, list_swap, list_symbol_to_c_abi, list_with_capacity,
|
||||
pass_update_mode,
|
||||
list_sort_with, list_sublist, list_swap, list_with_capacity, pass_update_mode,
|
||||
},
|
||||
build_str::call_str_from_utf_bitcode_fn,
|
||||
compare::{generic_eq, generic_neq},
|
||||
convert::{
|
||||
self, argument_type_from_layout, basic_type_from_layout, zig_num_parse_result_type,
|
||||
|
@ -396,46 +396,15 @@ pub(crate) fn run_low_level<'a, 'ctx>(
|
|||
)
|
||||
}
|
||||
StrFromUtf8 => {
|
||||
let result_type = env.module.get_struct_type("str.FromUtf8Result").unwrap();
|
||||
let result_ptr =
|
||||
create_entry_block_alloca(env, result_type, "alloca_utf8_validate_bytes_result");
|
||||
|
||||
use roc_target::Architecture::*;
|
||||
match env.target.architecture() {
|
||||
Aarch32 | X86_32 => {
|
||||
arguments!(list);
|
||||
let (a, b) = pass_list_or_string_to_zig_32bit(env, list.into_struct_value());
|
||||
|
||||
call_void_bitcode_fn(
|
||||
env,
|
||||
&[
|
||||
result_ptr.into(),
|
||||
a.into(),
|
||||
b.into(),
|
||||
pass_update_mode(env, update_mode),
|
||||
],
|
||||
bitcode::STR_FROM_UTF8,
|
||||
);
|
||||
}
|
||||
Aarch64 | X86_64 | Wasm32 => {
|
||||
arguments!(_list);
|
||||
|
||||
// we use the symbol here instead
|
||||
let list = args[0];
|
||||
|
||||
call_void_bitcode_fn(
|
||||
env,
|
||||
&[
|
||||
result_ptr.into(),
|
||||
list_symbol_to_c_abi(env, scope, list).into(),
|
||||
pass_update_mode(env, update_mode),
|
||||
],
|
||||
bitcode::STR_FROM_UTF8,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
crate::llvm::build_str::decode_from_utf8_result(env, layout_interner, result_ptr)
|
||||
// Str.from_utf8_lowlevel : List U8 -> FromUtf8Result
|
||||
arguments!(list);
|
||||
call_str_from_utf_bitcode_fn(
|
||||
env,
|
||||
layout_interner,
|
||||
&[list, pass_update_mode(env, update_mode)],
|
||||
"str.FromUtf8Result",
|
||||
bitcode::STR_FROM_UTF8,
|
||||
)
|
||||
}
|
||||
StrToUtf8 => {
|
||||
// Str.fromInt : Str -> List U8
|
||||
|
@ -449,6 +418,16 @@ pub(crate) fn run_low_level<'a, 'ctx>(
|
|||
bitcode::STR_TO_UTF8,
|
||||
)
|
||||
}
|
||||
StrFromUtf8Lossy => {
|
||||
arguments!(list);
|
||||
call_list_bitcode_fn(
|
||||
env,
|
||||
&[list.into_struct_value()],
|
||||
&[],
|
||||
BitcodeReturns::Str,
|
||||
bitcode::STR_FROM_UTF8_LOSSY,
|
||||
)
|
||||
}
|
||||
StrRepeat => {
|
||||
// Str.repeat : Str, U64 -> Str
|
||||
arguments!(string, count);
|
||||
|
@ -593,6 +572,7 @@ pub(crate) fn run_low_level<'a, 'ctx>(
|
|||
bitcode::STR_WITH_CAPACITY,
|
||||
)
|
||||
}
|
||||
|
||||
ListLenU64 => {
|
||||
// List.len : List * -> U64
|
||||
arguments!(list);
|
||||
|
@ -635,6 +615,39 @@ pub(crate) fn run_low_level<'a, 'ctx>(
|
|||
list_element_layout!(layout_interner, result_layout),
|
||||
)
|
||||
}
|
||||
StrWithAsciiLowercased => {
|
||||
arguments!(string);
|
||||
|
||||
call_str_bitcode_fn(
|
||||
env,
|
||||
&[string],
|
||||
&[],
|
||||
BitcodeReturns::Str,
|
||||
bitcode::STR_WITH_ASCII_LOWERCASED,
|
||||
)
|
||||
}
|
||||
StrWithAsciiUppercased => {
|
||||
arguments!(string);
|
||||
|
||||
call_str_bitcode_fn(
|
||||
env,
|
||||
&[string],
|
||||
&[],
|
||||
BitcodeReturns::Str,
|
||||
bitcode::STR_WITH_ASCII_UPPERCASED,
|
||||
)
|
||||
}
|
||||
StrCaselessAsciiEquals => {
|
||||
arguments!(string1, string2);
|
||||
|
||||
call_str_bitcode_fn(
|
||||
env,
|
||||
&[string1, string2],
|
||||
&[],
|
||||
BitcodeReturns::Basic,
|
||||
bitcode::STR_CASELESS_ASCII_EQUALS,
|
||||
)
|
||||
}
|
||||
ListConcat => {
|
||||
debug_assert_eq!(args.len(), 2);
|
||||
|
||||
|
@ -1284,30 +1297,6 @@ pub(crate) fn run_low_level<'a, 'ctx>(
|
|||
rhs_layout,
|
||||
)
|
||||
}
|
||||
And => {
|
||||
// The (&&) operator
|
||||
arguments!(lhs_arg, rhs_arg);
|
||||
|
||||
let bool_val = env.builder.new_build_and(
|
||||
lhs_arg.into_int_value(),
|
||||
rhs_arg.into_int_value(),
|
||||
"bool_and",
|
||||
);
|
||||
|
||||
BasicValueEnum::IntValue(bool_val)
|
||||
}
|
||||
Or => {
|
||||
// The (||) operator
|
||||
arguments!(lhs_arg, rhs_arg);
|
||||
|
||||
let bool_val = env.builder.new_build_or(
|
||||
lhs_arg.into_int_value(),
|
||||
rhs_arg.into_int_value(),
|
||||
"bool_or",
|
||||
);
|
||||
|
||||
BasicValueEnum::IntValue(bool_val)
|
||||
}
|
||||
Not => {
|
||||
// The (!) operator
|
||||
arguments!(arg);
|
||||
|
|
|
@ -245,6 +245,7 @@ impl<'a> LowLevelCall<'a> {
|
|||
backend.code_builder.i32_const(UPDATE_MODE_IMMUTABLE);
|
||||
backend.call_host_fn_after_loading_args(bitcode::STR_FROM_UTF8);
|
||||
}
|
||||
StrFromUtf8Lossy => self.load_args_and_call_zig(backend, bitcode::STR_FROM_UTF8_LOSSY),
|
||||
StrTrimStart => self.load_args_and_call_zig(backend, bitcode::STR_TRIM_START),
|
||||
StrTrimEnd => self.load_args_and_call_zig(backend, bitcode::STR_TRIM_END),
|
||||
StrToUtf8 => self.load_args_and_call_zig(backend, bitcode::STR_TO_UTF8),
|
||||
|
@ -258,6 +259,15 @@ impl<'a> LowLevelCall<'a> {
|
|||
self.load_args_and_call_zig(backend, bitcode::STR_SUBSTRING_UNSAFE)
|
||||
}
|
||||
StrWithCapacity => self.load_args_and_call_zig(backend, bitcode::STR_WITH_CAPACITY),
|
||||
StrWithAsciiLowercased => {
|
||||
self.load_args_and_call_zig(backend, bitcode::STR_WITH_ASCII_LOWERCASED)
|
||||
}
|
||||
StrWithAsciiUppercased => {
|
||||
self.load_args_and_call_zig(backend, bitcode::STR_WITH_ASCII_UPPERCASED)
|
||||
}
|
||||
StrCaselessAsciiEquals => {
|
||||
self.load_args_and_call_zig(backend, bitcode::STR_CASELESS_ASCII_EQUALS)
|
||||
}
|
||||
|
||||
// List
|
||||
ListLenU64 => {
|
||||
|
@ -2163,14 +2173,6 @@ impl<'a> LowLevelCall<'a> {
|
|||
NumF64ToParts => self.load_args_and_call_zig(backend, bitcode::NUM_F64_TO_PARTS),
|
||||
NumF32FromParts => self.load_args_and_call_zig(backend, bitcode::NUM_F32_FROM_PARTS),
|
||||
NumF64FromParts => self.load_args_and_call_zig(backend, bitcode::NUM_F64_FROM_PARTS),
|
||||
And => {
|
||||
self.load_args(backend);
|
||||
backend.code_builder.i32_and();
|
||||
}
|
||||
Or => {
|
||||
self.load_args(backend);
|
||||
backend.code_builder.i32_or();
|
||||
}
|
||||
Not => {
|
||||
self.load_args(backend);
|
||||
backend.code_builder.i32_eqz();
|
||||
|
|
|
@ -9,6 +9,7 @@ version.workspace = true
|
|||
|
||||
[dependencies]
|
||||
roc_can.workspace = true
|
||||
roc_can_solo.workspace = true
|
||||
roc_collections.workspace = true
|
||||
roc_load_internal.workspace = true
|
||||
roc_module.workspace = true
|
||||
|
|
|
@ -3,11 +3,12 @@ extern crate bumpalo;
|
|||
use self::bumpalo::Bump;
|
||||
use roc_can::abilities::AbilitiesStore;
|
||||
use roc_can::constraint::{Constraint, Constraints};
|
||||
use roc_can::desugar;
|
||||
use roc_can::env::Env;
|
||||
use roc_can::expected::Expected;
|
||||
use roc_can::expr::{canonicalize_expr, Expr, Output, PendingDerives};
|
||||
use roc_can::scope::Scope;
|
||||
use roc_can_solo::env::SoloEnv;
|
||||
use roc_can_solo::scope::SoloScope;
|
||||
use roc_collections::all::{ImMap, MutMap, SendSet};
|
||||
use roc_constrain::expr::constrain_expr;
|
||||
use roc_derive::SharedDerivedModule;
|
||||
|
@ -162,24 +163,6 @@ pub fn can_expr_with<'a>(
|
|||
// ensure the Test module is accessible in our tests
|
||||
module_ids.get_or_insert(&PQModuleName::Unqualified("Test".into()));
|
||||
|
||||
let mut scope = Scope::new(
|
||||
home,
|
||||
"TestPath".into(),
|
||||
IdentIds::default(),
|
||||
Default::default(),
|
||||
);
|
||||
|
||||
let dep_idents = IdentIds::exposed_builtins(0);
|
||||
let mut env = Env::new(
|
||||
arena,
|
||||
expr_str,
|
||||
home,
|
||||
Path::new("Test.roc"),
|
||||
&dep_idents,
|
||||
&module_ids,
|
||||
None,
|
||||
);
|
||||
|
||||
// Desugar operators (convert them to Apply calls, taking into account
|
||||
// operator precedence and associativity rules), before doing other canonicalization.
|
||||
//
|
||||
|
@ -187,7 +170,9 @@ pub fn can_expr_with<'a>(
|
|||
// visited a BinOp node we'd recursively try to apply this to each of its nested
|
||||
// operators, and then again on *their* nested operators, ultimately applying the
|
||||
// rules multiple times unnecessarily.
|
||||
let loc_expr = desugar::desugar_expr(&mut env, &mut scope, &loc_expr);
|
||||
let mut solo_env = SoloEnv::new(arena, expr_str, Path::new("Test.roc"));
|
||||
let mut solo_scope = SoloScope::new();
|
||||
let loc_expr = roc_can_solo::desugar::desugar_expr(&mut solo_env, &mut solo_scope, &loc_expr);
|
||||
|
||||
let mut scope = Scope::new(
|
||||
home,
|
||||
|
|
|
@ -1522,18 +1522,18 @@ mod test_reporting {
|
|||
from_annotation_if,
|
||||
indoc!(
|
||||
r"
|
||||
x : Num.Int *
|
||||
x : Num.Int _
|
||||
x = if Bool.true then 3.14 else 4
|
||||
|
||||
x
|
||||
"
|
||||
),
|
||||
@r"
|
||||
@r###"
|
||||
── TYPE MISMATCH in /code/proj/Main.roc ────────────────────────────────────────
|
||||
|
||||
Something is off with the `then` branch of this `if` expression:
|
||||
|
||||
4│ x : Num.Int *
|
||||
4│ x : Num.Int _
|
||||
5│ x = if Bool.true then 3.14 else 4
|
||||
^^^^
|
||||
|
||||
|
@ -1547,14 +1547,14 @@ mod test_reporting {
|
|||
|
||||
Tip: You can convert between integers and fractions using functions
|
||||
like `Num.to_frac` and `Num.round`.
|
||||
"
|
||||
"###
|
||||
);
|
||||
|
||||
test_report!(
|
||||
from_annotation_when,
|
||||
indoc!(
|
||||
r"
|
||||
x : Num.Int *
|
||||
x : Num.Int _
|
||||
x =
|
||||
when True is
|
||||
_ -> 3.14
|
||||
|
@ -1562,12 +1562,12 @@ mod test_reporting {
|
|||
x
|
||||
"
|
||||
),
|
||||
@r"
|
||||
@r###"
|
||||
── TYPE MISMATCH in /code/proj/Main.roc ────────────────────────────────────────
|
||||
|
||||
Something is off with the body of the `x` definition:
|
||||
|
||||
4│ x : Num.Int *
|
||||
4│ x : Num.Int _
|
||||
5│ x =
|
||||
6│> when True is
|
||||
7│> _ -> 3.14
|
||||
|
@ -1582,7 +1582,7 @@ mod test_reporting {
|
|||
|
||||
Tip: You can convert between integers and fractions using functions
|
||||
like `Num.to_frac` and `Num.round`.
|
||||
"
|
||||
"###
|
||||
);
|
||||
|
||||
test_report!(
|
||||
|
@ -1910,7 +1910,7 @@ mod test_reporting {
|
|||
from_annotation_complex_pattern,
|
||||
indoc!(
|
||||
r"
|
||||
{ x } : { x : Num.Int * }
|
||||
{ x } : { x : Num.Int _ }
|
||||
{ x } = { x: 4.0 }
|
||||
|
||||
x
|
||||
|
@ -1921,7 +1921,7 @@ mod test_reporting {
|
|||
|
||||
Something is off with the body of this definition:
|
||||
|
||||
4│ { x } : { x : Num.Int * }
|
||||
4│ { x } : { x : Num.Int _ }
|
||||
5│ { x } = { x: 4.0 }
|
||||
^^^^^^^^^^
|
||||
|
||||
|
@ -2047,18 +2047,18 @@ mod test_reporting {
|
|||
missing_fields,
|
||||
indoc!(
|
||||
r"
|
||||
x : { a : Num.Int *, b : Num.Frac *, c : Str }
|
||||
x : { a : Num.Int _, b : Num.Frac _, c : Str }
|
||||
x = { b: 4.0 }
|
||||
|
||||
x
|
||||
"
|
||||
),
|
||||
@r"
|
||||
@r###"
|
||||
── TYPE MISMATCH in /code/proj/Main.roc ────────────────────────────────────────
|
||||
|
||||
Something is off with the body of the `x` definition:
|
||||
|
||||
4│ x : { a : Num.Int *, b : Num.Frac *, c : Str }
|
||||
4│ x : { a : Num.Int _, b : Num.Frac _, c : Str }
|
||||
5│ x = { b: 4.0 }
|
||||
^^^^^^^^^^
|
||||
|
||||
|
@ -2075,7 +2075,7 @@ mod test_reporting {
|
|||
}
|
||||
|
||||
Tip: Looks like the c and a fields are missing.
|
||||
"
|
||||
"###
|
||||
);
|
||||
|
||||
// this previously reported the message below, not sure which is better
|
||||
|
@ -3448,7 +3448,7 @@ mod test_reporting {
|
|||
x : AList Num.I64 Num.I64
|
||||
x = ACons 0 (BCons 1 (ACons "foo" BNil ))
|
||||
|
||||
y : BList a a
|
||||
y : BList _ _
|
||||
y = BNil
|
||||
|
||||
{ x, y }
|
||||
|
@ -4189,9 +4189,8 @@ mod test_reporting {
|
|||
RBTree k v : [Node NodeColor k v (RBTree k v) (RBTree k v), Empty]
|
||||
|
||||
# Create an empty dictionary.
|
||||
empty : RBTree k v
|
||||
empty =
|
||||
Empty
|
||||
empty : {} -> RBTree k v
|
||||
empty = \{} -> Empty
|
||||
|
||||
empty
|
||||
"
|
||||
|
@ -6036,7 +6035,7 @@ All branches in an `if` must have the same type!
|
|||
double_binop,
|
||||
indoc!(
|
||||
r"
|
||||
key >= 97 && <= 122
|
||||
key >= 97 and <= 122
|
||||
"
|
||||
),
|
||||
@r"
|
||||
|
@ -6692,17 +6691,20 @@ All branches in an `if` must have the same type!
|
|||
)
|
||||
"
|
||||
),
|
||||
@r"
|
||||
── UNFINISHED FUNCTION in tmp/unfinished_closure_pattern_in_parens/Test.roc ────
|
||||
@r###"
|
||||
── MISSING ARROW in tmp/unfinished_closure_pattern_in_parens/Test.roc ──────────
|
||||
|
||||
I was partway through parsing a function, but I got stuck here:
|
||||
I am partway through parsing a function argument list, but I got stuck
|
||||
here:
|
||||
|
||||
4│ x = \( a
|
||||
5│ )
|
||||
^
|
||||
6│
|
||||
7│
|
||||
^
|
||||
|
||||
I just saw a pattern, so I was expecting to see a -> next.
|
||||
"
|
||||
I was expecting a -> next.
|
||||
"###
|
||||
);
|
||||
|
||||
test_report!(
|
||||
|
@ -11215,10 +11217,10 @@ All branches in an `if` must have the same type!
|
|||
|
||||
import Decode exposing [decoder]
|
||||
|
||||
main =
|
||||
my_decoder : Decoder (a -> a) fmt where fmt implements DecoderFormatting
|
||||
my_decoder = decoder
|
||||
my_decoder : Decoder (_ -> _) _
|
||||
my_decoder = decoder
|
||||
|
||||
main =
|
||||
my_decoder
|
||||
"#
|
||||
),
|
||||
|
@ -11227,12 +11229,12 @@ All branches in an `if` must have the same type!
|
|||
|
||||
This expression has a type that does not implement the abilities it's expected to:
|
||||
|
||||
7│ my_decoder = decoder
|
||||
^^^^^^^
|
||||
6│ my_decoder = decoder
|
||||
^^^^^^^
|
||||
|
||||
I can't generate an implementation of the `Decoding` ability for
|
||||
|
||||
a -> a
|
||||
* -> *
|
||||
|
||||
Note: `Decoding` cannot be generated for functions.
|
||||
"
|
||||
|
@ -11248,10 +11250,10 @@ All branches in an `if` must have the same type!
|
|||
|
||||
A := {}
|
||||
|
||||
main =
|
||||
my_decoder : Decoder {x : A} fmt where fmt implements DecoderFormatting
|
||||
my_decoder = decoder
|
||||
my_decoder : Decoder {x : A} _
|
||||
my_decoder = decoder
|
||||
|
||||
main =
|
||||
my_decoder
|
||||
"#
|
||||
),
|
||||
|
@ -11260,8 +11262,8 @@ All branches in an `if` must have the same type!
|
|||
|
||||
This expression has a type that does not implement the abilities it's expected to:
|
||||
|
||||
9│ my_decoder = decoder
|
||||
^^^^^^^
|
||||
8│ my_decoder = decoder
|
||||
^^^^^^^
|
||||
|
||||
I can't generate an implementation of the `Decoding` ability for
|
||||
|
||||
|
@ -11511,11 +11513,10 @@ All branches in an `if` must have the same type!
|
|||
|
||||
import Decode exposing [decoder]
|
||||
|
||||
main =
|
||||
my_decoder : Decoder {x : Str, y ? Str} fmt where fmt implements DecoderFormatting
|
||||
my_decoder = decoder
|
||||
my_decoder : Decoder {x : Str, y ? Str} _
|
||||
my_decoder = decoder
|
||||
|
||||
my_decoder
|
||||
main = my_decoder
|
||||
"#
|
||||
),
|
||||
@r"
|
||||
|
@ -11523,8 +11524,8 @@ All branches in an `if` must have the same type!
|
|||
|
||||
This expression has a type that does not implement the abilities it's expected to:
|
||||
|
||||
7│ my_decoder = decoder
|
||||
^^^^^^^
|
||||
6│ my_decoder = decoder
|
||||
^^^^^^^
|
||||
|
||||
I can't generate an implementation of the `Decoding` ability for
|
||||
|
||||
|
@ -14108,11 +14109,10 @@ All branches in an `if` must have the same type!
|
|||
|
||||
import Decode exposing [decoder]
|
||||
|
||||
main =
|
||||
my_decoder : Decoder (U32, Str) fmt where fmt implements DecoderFormatting
|
||||
my_decoder = decoder
|
||||
my_decoder : Decoder (U32, Str) _
|
||||
my_decoder = decoder
|
||||
|
||||
my_decoder
|
||||
main = my_decoder
|
||||
"#
|
||||
)
|
||||
);
|
||||
|
@ -14125,11 +14125,10 @@ All branches in an `if` must have the same type!
|
|||
|
||||
import Decode exposing [decoder]
|
||||
|
||||
main =
|
||||
my_decoder : Decoder (U32, {} -> {}) fmt where fmt implements DecoderFormatting
|
||||
my_decoder = decoder
|
||||
my_decoder : Decoder (U32, {} -> {}) _
|
||||
my_decoder = decoder
|
||||
|
||||
my_decoder
|
||||
main = my_decoder
|
||||
"#
|
||||
),
|
||||
@r"
|
||||
|
@ -14137,8 +14136,8 @@ All branches in an `if` must have the same type!
|
|||
|
||||
This expression has a type that does not implement the abilities it's expected to:
|
||||
|
||||
7│ my_decoder = decoder
|
||||
^^^^^^^
|
||||
6│ my_decoder = decoder
|
||||
^^^^^^^
|
||||
|
||||
I can't generate an implementation of the `Decoding` ability for
|
||||
|
||||
|
@ -15994,4 +15993,66 @@ All branches in an `if` must have the same type!
|
|||
Str -> {}
|
||||
"#
|
||||
);
|
||||
|
||||
test_report!(
|
||||
invalid_generic_literal,
|
||||
indoc!(
|
||||
r#"
|
||||
module [v]
|
||||
|
||||
v : *
|
||||
v = 1
|
||||
"#
|
||||
),
|
||||
@r###"
|
||||
── TYPE MISMATCH in /code/proj/Main.roc ────────────────────────────────────────
|
||||
|
||||
Something is off with the body of the `v` definition:
|
||||
|
||||
3│ v : *
|
||||
4│ v = 1
|
||||
^
|
||||
|
||||
The body is a number of type:
|
||||
|
||||
Num *
|
||||
|
||||
But the type annotation on `v` says it should be:
|
||||
|
||||
*
|
||||
|
||||
Tip: The type annotation uses the type variable `*` to say that this
|
||||
definition can produce any type of value. But in the body I see that
|
||||
it will only produce a `Num` value of a single specific type. Maybe
|
||||
change the type annotation to be more specific? Maybe change the code
|
||||
to be more general?
|
||||
"###
|
||||
);
|
||||
|
||||
test_report!(
|
||||
invalid_generic_literal_list,
|
||||
indoc!(
|
||||
r#"
|
||||
module [v]
|
||||
|
||||
v : List *
|
||||
v = []
|
||||
"#
|
||||
),
|
||||
@r###"
|
||||
── TYPE VARIABLE IS NOT GENERIC in /code/proj/Main.roc ─────────────────────────
|
||||
|
||||
This type variable has a single type:
|
||||
|
||||
3│ v : List *
|
||||
^
|
||||
|
||||
Type variables tell me that they can be used with any type, but they
|
||||
can only be used with functions. All other values have exactly one
|
||||
type.
|
||||
|
||||
Hint: If you would like the type to be inferred for you, use an
|
||||
underscore _ instead.
|
||||
"###
|
||||
);
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@ version.workspace = true
|
|||
[dependencies]
|
||||
roc_builtins.workspace = true
|
||||
roc_can.workspace = true
|
||||
roc_can_solo.workspace = true
|
||||
roc_work.workspace = true
|
||||
roc_checkmate.workspace = true
|
||||
roc_collections.workspace = true
|
||||
|
@ -39,6 +40,8 @@ bumpalo.workspace = true
|
|||
crossbeam.workspace = true
|
||||
parking_lot.workspace = true
|
||||
tempfile.workspace = true
|
||||
base64-url.workspace = true
|
||||
blake3.workspace = true
|
||||
|
||||
[dev-dependencies]
|
||||
roc_test_utils_dir.workspace = true
|
||||
|
|
|
@ -15,11 +15,14 @@ use parking_lot::Mutex;
|
|||
use roc_builtins::roc::module_source;
|
||||
use roc_can::abilities::{AbilitiesStore, PendingAbilitiesStore, ResolvedImpl};
|
||||
use roc_can::constraint::{Constraint as ConstraintSoa, Constraints, TypeOrVar};
|
||||
use roc_can::env::Env;
|
||||
use roc_can::expr::{Declarations, ExpectLookup, PendingDerives};
|
||||
use roc_can::module::{
|
||||
canonicalize_module_defs, ExposedByModule, ExposedForModule, ExposedModuleTypes, Module,
|
||||
ModuleParams, ResolvedImplementations, TypeState,
|
||||
};
|
||||
use roc_can::scope::Scope;
|
||||
use roc_can_solo::module::{solo_canonicalize_module_defs, SoloCanOutput};
|
||||
use roc_collections::soa::slice_extend_new;
|
||||
use roc_collections::{default_hasher, BumpMap, MutMap, MutSet, VecMap, VecSet};
|
||||
use roc_constrain::module::constrain_module;
|
||||
|
@ -204,9 +207,20 @@ fn start_phase<'a>(
|
|||
root_type: state.root_type.clone(),
|
||||
}
|
||||
}
|
||||
Phase::SoloCanonicalize => {
|
||||
// canonicalize the file
|
||||
let parsed = state.module_cache.parsed.get(&module_id).unwrap().clone();
|
||||
|
||||
BuildTask::SoloCanonicalize { parsed }
|
||||
}
|
||||
Phase::CanonicalizeAndConstrain => {
|
||||
// canonicalize the file
|
||||
let parsed = state.module_cache.parsed.remove(&module_id).unwrap();
|
||||
let solo_can_output = state
|
||||
.module_cache
|
||||
.solo_canonicalized
|
||||
.remove(&module_id)
|
||||
.unwrap();
|
||||
|
||||
let deps_by_name = &parsed.deps_by_name;
|
||||
let num_deps = deps_by_name.len();
|
||||
|
@ -318,6 +332,7 @@ fn start_phase<'a>(
|
|||
exposed_module_ids: state.exposed_modules,
|
||||
exec_mode: state.exec_mode,
|
||||
imported_module_params,
|
||||
solo_can_output,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -577,6 +592,7 @@ enum Msg<'a> {
|
|||
Many(Vec<Msg<'a>>),
|
||||
Header(ModuleHeader<'a>),
|
||||
Parsed(ParsedModule<'a>),
|
||||
SoloCanonicalized(ModuleId, CanSolo<'a>),
|
||||
CanonicalizedAndConstrained(CanAndCon),
|
||||
SolvedTypes {
|
||||
module_id: ModuleId,
|
||||
|
@ -651,6 +667,9 @@ enum Msg<'a> {
|
|||
IncorrectModuleName(FileError<'a, IncorrectModuleName<'a>>),
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct CanSolo<'a>(SoloCanOutput<'a>);
|
||||
|
||||
#[derive(Debug)]
|
||||
struct CanAndCon {
|
||||
constrained_module: ConstrainedModule,
|
||||
|
@ -890,6 +909,9 @@ enum BuildTask<'a> {
|
|||
ident_ids_by_module: SharedIdentIdsByModule,
|
||||
root_type: RootType,
|
||||
},
|
||||
SoloCanonicalize {
|
||||
parsed: ParsedModule<'a>,
|
||||
},
|
||||
CanonicalizeAndConstrain {
|
||||
parsed: ParsedModule<'a>,
|
||||
qualified_module_ids: PackageModuleIds<'a>,
|
||||
|
@ -901,6 +923,7 @@ enum BuildTask<'a> {
|
|||
skip_constraint_gen: bool,
|
||||
exec_mode: ExecutionMode,
|
||||
imported_module_params: VecMap<ModuleId, ModuleParams>,
|
||||
solo_can_output: SoloCanOutput<'a>,
|
||||
},
|
||||
Solve {
|
||||
module: Module,
|
||||
|
@ -2411,6 +2434,23 @@ fn update<'a>(
|
|||
Ok(state)
|
||||
}
|
||||
|
||||
SoloCanonicalized(module_id, CanSolo(solo_can_output)) => {
|
||||
log!("solo canonicalized module {:?}", module_id);
|
||||
|
||||
state
|
||||
.module_cache
|
||||
.solo_canonicalized
|
||||
.insert(module_id, solo_can_output);
|
||||
|
||||
let work = state
|
||||
.dependencies
|
||||
.notify(module_id, Phase::SoloCanonicalize);
|
||||
|
||||
start_tasks(arena, &mut state, work, injector, worker_wakers)?;
|
||||
|
||||
Ok(state)
|
||||
}
|
||||
|
||||
CanonicalizedAndConstrained(CanAndCon {
|
||||
constrained_module,
|
||||
canonicalization_problems,
|
||||
|
@ -2462,6 +2502,7 @@ fn update<'a>(
|
|||
|
||||
Ok(state)
|
||||
}
|
||||
|
||||
SolvedTypes {
|
||||
module_id,
|
||||
ident_ids,
|
||||
|
@ -5082,6 +5123,31 @@ fn build_platform_header<'a>(
|
|||
build_header(info, parse_state, module_ids, module_timing)
|
||||
}
|
||||
|
||||
#[allow(clippy::unnecessary_wraps)]
|
||||
fn canonicalize_solo<'a>(arena: &'a Bump, parsed: ParsedModule<'a>) -> CanSolo<'a> {
|
||||
let canonicalize_solo_start = Instant::now();
|
||||
|
||||
let ParsedModule {
|
||||
module_path,
|
||||
header_type,
|
||||
src,
|
||||
parsed_defs,
|
||||
mut module_timing,
|
||||
..
|
||||
} = parsed;
|
||||
|
||||
let parsed_defs = arena.alloc(parsed_defs);
|
||||
|
||||
let solo_can_output =
|
||||
solo_canonicalize_module_defs(arena, header_type, parsed_defs, module_path, src);
|
||||
|
||||
let canonicalize_solo_end = Instant::now();
|
||||
|
||||
module_timing.canonicalize_solo = canonicalize_solo_end.duration_since(canonicalize_solo_start);
|
||||
|
||||
CanSolo(solo_can_output)
|
||||
}
|
||||
|
||||
#[allow(clippy::unnecessary_wraps)]
|
||||
fn canonicalize_and_constrain<'a>(
|
||||
arena: &'a Bump,
|
||||
|
@ -5095,21 +5161,21 @@ fn canonicalize_and_constrain<'a>(
|
|||
exposed_module_ids: &[ModuleId],
|
||||
exec_mode: ExecutionMode,
|
||||
imported_module_params: VecMap<ModuleId, ModuleParams>,
|
||||
solo_can_output: SoloCanOutput<'a>,
|
||||
) -> CanAndCon {
|
||||
let canonicalize_start = Instant::now();
|
||||
|
||||
let ParsedModule {
|
||||
module_id,
|
||||
module_path,
|
||||
src,
|
||||
header_type,
|
||||
exposed_ident_ids,
|
||||
parsed_defs,
|
||||
initial_scope,
|
||||
available_modules,
|
||||
mut module_timing,
|
||||
symbols_from_requires,
|
||||
opt_shorthand,
|
||||
exposed_ident_ids,
|
||||
..
|
||||
} = parsed;
|
||||
|
||||
|
@ -5117,27 +5183,55 @@ fn canonicalize_and_constrain<'a>(
|
|||
let _before = roc_types::types::get_type_clone_count();
|
||||
|
||||
let parsed_defs_for_docs = parsed_defs.clone();
|
||||
let parsed_defs = arena.alloc(parsed_defs);
|
||||
|
||||
let mut var_store = VarStore::default();
|
||||
|
||||
let env = Env::from_solo_can(
|
||||
arena,
|
||||
&module_path,
|
||||
module_id,
|
||||
&dep_idents,
|
||||
qualified_module_ids,
|
||||
solo_can_output.problems,
|
||||
opt_shorthand,
|
||||
solo_can_output.src,
|
||||
solo_can_output.lazy_line_info,
|
||||
);
|
||||
|
||||
let mut scope = Scope::new(
|
||||
module_id,
|
||||
qualified_module_ids
|
||||
.get_name(module_id)
|
||||
.expect("home module not found")
|
||||
.as_inner()
|
||||
.to_owned(),
|
||||
exposed_ident_ids,
|
||||
imported_abilities_state,
|
||||
);
|
||||
|
||||
for (name, alias) in aliases.into_iter() {
|
||||
scope.add_alias(
|
||||
name,
|
||||
alias.region,
|
||||
alias.type_variables,
|
||||
alias.infer_ext_in_output_variables,
|
||||
alias.typ,
|
||||
alias.kind,
|
||||
);
|
||||
}
|
||||
|
||||
let mut module_output = canonicalize_module_defs(
|
||||
arena,
|
||||
parsed_defs,
|
||||
&header_type,
|
||||
module_id,
|
||||
&*arena.alloc(module_path.to_string_lossy()),
|
||||
src,
|
||||
qualified_module_ids,
|
||||
exposed_ident_ids,
|
||||
&dep_idents,
|
||||
aliases,
|
||||
imported_abilities_state,
|
||||
initial_scope,
|
||||
exposed_symbols,
|
||||
&symbols_from_requires,
|
||||
&mut var_store,
|
||||
opt_shorthand,
|
||||
scope,
|
||||
env,
|
||||
solo_can_output.loc_defs,
|
||||
solo_can_output.module_params,
|
||||
);
|
||||
|
||||
let mut types = Types::new();
|
||||
|
@ -6237,6 +6331,12 @@ fn run_task<'a>(
|
|||
ident_ids_by_module,
|
||||
root_type,
|
||||
),
|
||||
SoloCanonicalize { parsed } => {
|
||||
let module_id = parsed.module_id;
|
||||
let solo_can = canonicalize_solo(arena, parsed);
|
||||
|
||||
Ok(Msg::SoloCanonicalized(module_id, solo_can))
|
||||
}
|
||||
CanonicalizeAndConstrain {
|
||||
parsed,
|
||||
qualified_module_ids,
|
||||
|
@ -6248,6 +6348,7 @@ fn run_task<'a>(
|
|||
exposed_module_ids,
|
||||
exec_mode,
|
||||
imported_module_params,
|
||||
solo_can_output,
|
||||
} => {
|
||||
let can_and_con = canonicalize_and_constrain(
|
||||
arena,
|
||||
|
@ -6261,6 +6362,7 @@ fn run_task<'a>(
|
|||
exposed_module_ids,
|
||||
exec_mode,
|
||||
imported_module_params,
|
||||
solo_can_output,
|
||||
);
|
||||
|
||||
Ok(Msg::CanonicalizedAndConstrained(can_and_con))
|
||||
|
|
|
@ -189,7 +189,7 @@ pub struct MonomorphizedModule<'a> {
|
|||
pub glue_layouts: GlueLayouts<'a>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ParsedModule<'a> {
|
||||
pub module_id: ModuleId,
|
||||
pub module_path: PathBuf,
|
||||
|
@ -237,11 +237,12 @@ pub struct ExposedToHost {
|
|||
pub getters: Vec<Symbol>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ModuleTiming {
|
||||
pub read_roc_file: Duration,
|
||||
pub parse_header: Duration,
|
||||
pub parse_body: Duration,
|
||||
pub canonicalize_solo: Duration,
|
||||
pub canonicalize: Duration,
|
||||
pub constrain: Duration,
|
||||
pub solve: Duration,
|
||||
|
@ -261,6 +262,7 @@ impl ModuleTiming {
|
|||
read_roc_file: Duration::default(),
|
||||
parse_header: Duration::default(),
|
||||
parse_body: Duration::default(),
|
||||
canonicalize_solo: Duration::default(),
|
||||
canonicalize: Duration::default(),
|
||||
constrain: Duration::default(),
|
||||
solve: Duration::default(),
|
||||
|
@ -281,6 +283,7 @@ impl ModuleTiming {
|
|||
read_roc_file,
|
||||
parse_header,
|
||||
parse_body,
|
||||
canonicalize_solo,
|
||||
canonicalize,
|
||||
constrain,
|
||||
solve,
|
||||
|
@ -297,6 +300,7 @@ impl ModuleTiming {
|
|||
.checked_sub(*find_specializations)?
|
||||
.checked_sub(*solve)?
|
||||
.checked_sub(*constrain)?
|
||||
.checked_sub(*canonicalize_solo)?
|
||||
.checked_sub(*canonicalize)?
|
||||
.checked_sub(*parse_body)?
|
||||
.checked_sub(*parse_header)?
|
||||
|
|
|
@ -5,6 +5,7 @@ use crate::module::{
|
|||
};
|
||||
use roc_can::abilities::PendingAbilitiesStore;
|
||||
use roc_can::module::ModuleParams;
|
||||
use roc_can_solo::module::SoloCanOutput;
|
||||
use roc_collections::{MutMap, MutSet, VecMap};
|
||||
use roc_module::ident::ModuleName;
|
||||
use roc_module::symbol::{ModuleId, PQModuleName, Symbol};
|
||||
|
@ -26,6 +27,7 @@ pub(crate) struct ModuleCache<'a> {
|
|||
pub(crate) parsed: MutMap<ModuleId, ParsedModule<'a>>,
|
||||
pub(crate) aliases: MutMap<ModuleId, MutMap<Symbol, (bool, Alias)>>,
|
||||
pub(crate) pending_abilities: MutMap<ModuleId, PendingAbilitiesStore>,
|
||||
pub(crate) solo_canonicalized: MutMap<ModuleId, SoloCanOutput<'a>>,
|
||||
pub(crate) constrained: MutMap<ModuleId, ConstrainedModule>,
|
||||
pub(crate) module_params: MutMap<ModuleId, ModuleParams>,
|
||||
pub(crate) typechecked: MutMap<ModuleId, TypeCheckedModule<'a>>,
|
||||
|
@ -45,6 +47,8 @@ pub(crate) struct ModuleCache<'a> {
|
|||
pub(crate) type_problems: MutMap<ModuleId, Vec<TypeError>>,
|
||||
|
||||
pub(crate) sources: MutMap<ModuleId, (PathBuf, &'a str)>,
|
||||
#[allow(dead_code)]
|
||||
pub(crate) content_hashes: MutMap<ModuleId, String>,
|
||||
}
|
||||
|
||||
impl<'a> ModuleCache<'a> {
|
||||
|
@ -65,6 +69,19 @@ impl<'a> ModuleCache<'a> {
|
|||
pub fn has_errors(&self) -> bool {
|
||||
self.has_can_errors() || self.has_type_errors()
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn add_module_content_hash(&mut self, module_id: ModuleId, contents: &str) -> String {
|
||||
let hash = Self::hash_contents(contents);
|
||||
self.content_hashes.insert(module_id, hash.clone());
|
||||
|
||||
hash
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn hash_contents(contents: &str) -> String {
|
||||
base64_url::encode(blake3::hash(contents.as_bytes()).as_bytes())
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for ModuleCache<'_> {
|
||||
|
@ -101,6 +118,7 @@ impl Default for ModuleCache<'_> {
|
|||
parsed: Default::default(),
|
||||
aliases: Default::default(),
|
||||
pending_abilities: Default::default(),
|
||||
solo_canonicalized: Default::default(),
|
||||
constrained: Default::default(),
|
||||
module_params: Default::default(),
|
||||
typechecked: Default::default(),
|
||||
|
@ -116,6 +134,7 @@ impl Default for ModuleCache<'_> {
|
|||
can_problems: Default::default(),
|
||||
type_problems: Default::default(),
|
||||
sources: Default::default(),
|
||||
content_hashes: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,7 +24,7 @@ succeed = \x -> Identity(x)
|
|||
|
||||
with_default = Res.with_default
|
||||
|
||||
yay : Res.Res {} err
|
||||
yay : Res.Res {} _
|
||||
yay =
|
||||
ok = Ok("foo")
|
||||
|
||||
|
|
|
@ -24,7 +24,7 @@ succeed = \x -> Identity(x)
|
|||
|
||||
with_default = Res.with_default
|
||||
|
||||
yay : Res.Res {} err
|
||||
yay : Res.Res {} _
|
||||
yay =
|
||||
ok = Ok("foo")
|
||||
|
||||
|
|
|
@ -271,11 +271,13 @@ fn load_fixture(
|
|||
);
|
||||
}
|
||||
|
||||
assert!(loaded_module
|
||||
.type_problems
|
||||
.remove(&home)
|
||||
.unwrap_or_default()
|
||||
.is_empty());
|
||||
assert_eq!(
|
||||
loaded_module
|
||||
.type_problems
|
||||
.remove(&home)
|
||||
.unwrap_or_default(),
|
||||
Vec::new()
|
||||
);
|
||||
|
||||
let expected_name = loaded_module
|
||||
.interns
|
||||
|
@ -433,11 +435,13 @@ fn module_with_deps() {
|
|||
loaded_module.can_problems.remove(&home).unwrap_or_default(),
|
||||
Vec::new()
|
||||
);
|
||||
assert!(loaded_module
|
||||
.type_problems
|
||||
.remove(&home)
|
||||
.unwrap_or_default()
|
||||
.is_empty(),);
|
||||
assert_eq!(
|
||||
loaded_module
|
||||
.type_problems
|
||||
.remove(&home)
|
||||
.unwrap_or_default(),
|
||||
Vec::new()
|
||||
);
|
||||
|
||||
let mut def_count = 0;
|
||||
let declarations = loaded_module.declarations_by_id.remove(&home).unwrap();
|
||||
|
|
|
@ -105,7 +105,8 @@ pub fn remove_module_param_arguments(
|
|||
| TypeError::ExpectedEffectful(_, _)
|
||||
| TypeError::UnsuffixedEffectfulFunction(_, _)
|
||||
| TypeError::SuffixedPureFunction(_, _)
|
||||
| TypeError::InvalidTryTarget(_, _, _) => {}
|
||||
| TypeError::InvalidTryTarget(_, _, _)
|
||||
| TypeError::TypeIsNotGeneralized(..) => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -213,6 +214,7 @@ fn drop_last_argument(err_type: &mut ErrorType) {
|
|||
| ErrorType::Alias(_, _, _, _)
|
||||
| ErrorType::Range(_)
|
||||
| ErrorType::Error
|
||||
| ErrorType::EffectfulFunc => {}
|
||||
| ErrorType::EffectfulFunc
|
||||
| ErrorType::InferenceVar => {}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@ use self::BinOp::*;
|
|||
use std::cmp::Ordering;
|
||||
use std::fmt;
|
||||
|
||||
const PRECEDENCES: [(BinOp, u8); 17] = [
|
||||
const PRECEDENCES: [(BinOp, u8); 18] = [
|
||||
(Caret, 8),
|
||||
(Star, 7),
|
||||
(Slash, 7),
|
||||
|
@ -12,6 +12,7 @@ const PRECEDENCES: [(BinOp, u8); 17] = [
|
|||
(Plus, 5),
|
||||
(Minus, 5),
|
||||
(DoubleQuestion, 5),
|
||||
(SingleQuestion, 5),
|
||||
(Pizza, 4),
|
||||
(Equals, 3),
|
||||
(NotEquals, 3),
|
||||
|
@ -23,7 +24,7 @@ const PRECEDENCES: [(BinOp, u8); 17] = [
|
|||
(Or, 0),
|
||||
];
|
||||
|
||||
const ASSOCIATIVITIES: [(BinOp, Associativity); 17] = [
|
||||
const ASSOCIATIVITIES: [(BinOp, Associativity); 18] = [
|
||||
(Caret, RightAssociative),
|
||||
(Star, LeftAssociative),
|
||||
(Slash, LeftAssociative),
|
||||
|
@ -32,6 +33,7 @@ const ASSOCIATIVITIES: [(BinOp, Associativity); 17] = [
|
|||
(Plus, LeftAssociative),
|
||||
(Minus, LeftAssociative),
|
||||
(DoubleQuestion, LeftAssociative),
|
||||
(SingleQuestion, LeftAssociative),
|
||||
(Pizza, LeftAssociative),
|
||||
(Equals, NonAssociative),
|
||||
(NotEquals, NonAssociative),
|
||||
|
@ -43,7 +45,7 @@ const ASSOCIATIVITIES: [(BinOp, Associativity); 17] = [
|
|||
(Or, RightAssociative),
|
||||
];
|
||||
|
||||
const DISPLAY_STRINGS: [(BinOp, &str); 17] = [
|
||||
const DISPLAY_STRINGS: [(BinOp, &str); 18] = [
|
||||
(Caret, "^"),
|
||||
(Star, "*"),
|
||||
(Slash, "/"),
|
||||
|
@ -52,6 +54,7 @@ const DISPLAY_STRINGS: [(BinOp, &str); 17] = [
|
|||
(Plus, "+"),
|
||||
(Minus, "-"),
|
||||
(DoubleQuestion, "??"),
|
||||
(SingleQuestion, "?"),
|
||||
(Pizza, "|>"),
|
||||
(Equals, "=="),
|
||||
(NotEquals, "!="),
|
||||
|
@ -59,8 +62,8 @@ const DISPLAY_STRINGS: [(BinOp, &str); 17] = [
|
|||
(GreaterThan, ">"),
|
||||
(LessThanOrEq, "<="),
|
||||
(GreaterThanOrEq, ">="),
|
||||
(And, "&&"),
|
||||
(Or, "||"),
|
||||
(And, "and"),
|
||||
(Or, "or"),
|
||||
];
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
|
@ -154,6 +157,7 @@ pub enum BinOp {
|
|||
Plus,
|
||||
Minus,
|
||||
DoubleQuestion,
|
||||
SingleQuestion,
|
||||
Pizza,
|
||||
Equals,
|
||||
NotEquals,
|
||||
|
@ -170,7 +174,8 @@ impl BinOp {
|
|||
/// how wide this operator is when typed out
|
||||
pub fn width(self) -> u16 {
|
||||
match self {
|
||||
Caret | Star | Slash | Percent | Plus | Minus | LessThan | GreaterThan => 1,
|
||||
Caret | Star | Slash | Percent | Plus | Minus | LessThan | GreaterThan
|
||||
| SingleQuestion => 1,
|
||||
DoubleSlash | Equals | NotEquals | LessThanOrEq | GreaterThanOrEq | And | Or
|
||||
| Pizza | DoubleQuestion => 2,
|
||||
}
|
||||
|
@ -194,7 +199,7 @@ pub enum Associativity {
|
|||
/// right-associative operators:
|
||||
///
|
||||
/// exponentiation: ^
|
||||
/// boolean: && ||
|
||||
/// boolean: and or
|
||||
/// application: <|
|
||||
RightAssociative,
|
||||
|
||||
|
@ -206,13 +211,13 @@ pub enum Associativity {
|
|||
|
||||
impl BinOp {
|
||||
pub fn associativity(self) -> Associativity {
|
||||
const ASSOCIATIVITY_TABLE: [Associativity; 17] = generate_associativity_table();
|
||||
const ASSOCIATIVITY_TABLE: [Associativity; 18] = generate_associativity_table();
|
||||
|
||||
ASSOCIATIVITY_TABLE[self as usize]
|
||||
}
|
||||
|
||||
fn precedence(self) -> u8 {
|
||||
const PRECEDENCE_TABLE: [u8; 17] = generate_precedence_table();
|
||||
const PRECEDENCE_TABLE: [u8; 18] = generate_precedence_table();
|
||||
|
||||
PRECEDENCE_TABLE[self as usize]
|
||||
}
|
||||
|
@ -232,14 +237,14 @@ impl Ord for BinOp {
|
|||
|
||||
impl std::fmt::Display for BinOp {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
const DISPLAY_TABLE: [&str; 17] = generate_display_table();
|
||||
const DISPLAY_TABLE: [&str; 18] = generate_display_table();
|
||||
|
||||
write!(f, "{}", DISPLAY_TABLE[*self as usize])
|
||||
}
|
||||
}
|
||||
|
||||
const fn generate_precedence_table() -> [u8; 17] {
|
||||
let mut table = [0u8; 17];
|
||||
const fn generate_precedence_table() -> [u8; 18] {
|
||||
let mut table = [0u8; 18];
|
||||
let mut i = 0;
|
||||
|
||||
while i < PRECEDENCES.len() {
|
||||
|
@ -250,8 +255,8 @@ const fn generate_precedence_table() -> [u8; 17] {
|
|||
table
|
||||
}
|
||||
|
||||
const fn generate_associativity_table() -> [Associativity; 17] {
|
||||
let mut table = [NonAssociative; 17];
|
||||
const fn generate_associativity_table() -> [Associativity; 18] {
|
||||
let mut table = [NonAssociative; 18];
|
||||
let mut i = 0;
|
||||
|
||||
while i < ASSOCIATIVITIES.len() {
|
||||
|
@ -262,8 +267,8 @@ const fn generate_associativity_table() -> [Associativity; 17] {
|
|||
table
|
||||
}
|
||||
|
||||
const fn generate_display_table() -> [&'static str; 17] {
|
||||
let mut table = [""; 17];
|
||||
const fn generate_display_table() -> [&'static str; 18] {
|
||||
let mut table = [""; 18];
|
||||
let mut i = 0;
|
||||
|
||||
while i < DISPLAY_STRINGS.len() {
|
||||
|
|
|
@ -14,6 +14,7 @@ pub enum LowLevel {
|
|||
StrCountUtf8Bytes,
|
||||
StrFromInt,
|
||||
StrFromUtf8,
|
||||
StrFromUtf8Lossy,
|
||||
StrToUtf8,
|
||||
StrRepeat,
|
||||
StrFromFloat,
|
||||
|
@ -26,6 +27,9 @@ pub enum LowLevel {
|
|||
StrReserve,
|
||||
StrWithCapacity,
|
||||
StrReleaseExcessCapacity,
|
||||
StrWithAsciiLowercased,
|
||||
StrWithAsciiUppercased,
|
||||
StrCaselessAsciiEquals,
|
||||
ListLenUsize,
|
||||
ListLenU64,
|
||||
ListWithCapacity,
|
||||
|
@ -109,8 +113,6 @@ pub enum LowLevel {
|
|||
NumF64FromParts,
|
||||
Eq,
|
||||
NotEq,
|
||||
And,
|
||||
Or,
|
||||
Not,
|
||||
Hash,
|
||||
PtrCast,
|
||||
|
@ -256,6 +258,7 @@ map_symbol_to_lowlevel! {
|
|||
StrSplitOn <= STR_SPLIT_ON;
|
||||
StrCountUtf8Bytes <= STR_COUNT_UTF8_BYTES;
|
||||
StrFromUtf8 <= STR_FROM_UTF8_LOWLEVEL;
|
||||
StrFromUtf8Lossy <= STR_FROM_UTF8_LOSSY;
|
||||
StrToUtf8 <= STR_TO_UTF8;
|
||||
StrRepeat <= STR_REPEAT;
|
||||
StrTrim <= STR_TRIM;
|
||||
|
@ -267,6 +270,9 @@ map_symbol_to_lowlevel! {
|
|||
StrToNum <= STR_TO_NUM;
|
||||
StrWithCapacity <= STR_WITH_CAPACITY;
|
||||
StrReleaseExcessCapacity <= STR_RELEASE_EXCESS_CAPACITY;
|
||||
StrWithAsciiLowercased <= STR_WITH_ASCII_LOWERCASED;
|
||||
StrWithAsciiUppercased <= STR_WITH_ASCII_UPPERCASED;
|
||||
StrCaselessAsciiEquals <= STR_CASELESS_ASCII_EQUALS;
|
||||
ListLenU64 <= LIST_LEN_U64;
|
||||
ListLenUsize <= LIST_LEN_USIZE;
|
||||
ListGetCapacity <= LIST_CAPACITY;
|
||||
|
@ -343,8 +349,6 @@ map_symbol_to_lowlevel! {
|
|||
NumF64FromParts <= NUM_F64_FROM_PARTS;
|
||||
Eq <= BOOL_STRUCTURAL_EQ;
|
||||
NotEq <= BOOL_STRUCTURAL_NOT_EQ;
|
||||
And <= BOOL_AND;
|
||||
Or <= BOOL_OR;
|
||||
Not <= BOOL_NOT;
|
||||
Unreachable <= LIST_UNREACHABLE;
|
||||
DictPseudoSeed <= DICT_PSEUDO_SEED;
|
||||
|
|
|
@ -986,6 +986,10 @@ macro_rules! define_builtins {
|
|||
self.to_zero_indexed() < $total
|
||||
}
|
||||
|
||||
pub const fn first_after_builtins() -> Self {
|
||||
ModuleId::from_zero_indexed($total)
|
||||
}
|
||||
|
||||
$(
|
||||
pub const $module_const: ModuleId = ModuleId::from_zero_indexed($module_id);
|
||||
)+
|
||||
|
@ -1355,16 +1359,14 @@ define_builtins! {
|
|||
0 BOOL_BOOL: "Bool" exposed_type=true // the Bool.Bool type alias
|
||||
1 BOOL_FALSE: "false"
|
||||
2 BOOL_TRUE: "true"
|
||||
3 BOOL_AND: "and"
|
||||
4 BOOL_OR: "or"
|
||||
5 BOOL_NOT: "not"
|
||||
6 BOOL_XOR: "xor"
|
||||
7 BOOL_NEQ: "is_not_eq"
|
||||
8 BOOL_EQ: "Eq" exposed_type=true
|
||||
9 BOOL_IS_EQ: "is_eq"
|
||||
10 BOOL_IS_EQ_IMPL: "bool_is_eq"
|
||||
unexposed 11 BOOL_STRUCTURAL_EQ: "structural_eq"
|
||||
unexposed 12 BOOL_STRUCTURAL_NOT_EQ: "structural_not_eq"
|
||||
3 BOOL_NOT: "not"
|
||||
4 BOOL_XOR: "xor"
|
||||
5 BOOL_NEQ: "is_not_eq"
|
||||
6 BOOL_EQ: "Eq" exposed_type=true
|
||||
7 BOOL_IS_EQ: "is_eq"
|
||||
8 BOOL_IS_EQ_IMPL: "bool_is_eq"
|
||||
unexposed 9 BOOL_STRUCTURAL_EQ: "structural_eq"
|
||||
unexposed 10 BOOL_STRUCTURAL_NOT_EQ: "structural_not_eq"
|
||||
}
|
||||
5 STR: "Str" => {
|
||||
0 STR_STR: "Str" exposed_apply_type=true // the Str.Str type alias
|
||||
|
@ -1377,8 +1379,8 @@ define_builtins! {
|
|||
7 STR_STARTS_WITH: "starts_with"
|
||||
8 STR_ENDS_WITH: "ends_with"
|
||||
9 STR_FROM_UTF8: "from_utf8"
|
||||
10 STR_UT8_PROBLEM: "Utf8Problem" // the Utf8Problem type alias
|
||||
11 STR_UT8_BYTE_PROBLEM: "Utf8ByteProblem" // the Utf8ByteProblem type alias
|
||||
10 STR_FROM_UTF8_LOSSY: "from_utf8_lossy"
|
||||
11 STR_UTF8_BYTE_PROBLEM: "Utf8Problem"
|
||||
12 STR_TO_UTF8: "to_utf8"
|
||||
13 STR_WALK_UTF8: "walk_utf8"
|
||||
14 STR_ALIAS_ANALYSIS_STATIC: "#aliasAnalysisStatic" // string with the static lifetime
|
||||
|
@ -1418,6 +1420,13 @@ define_builtins! {
|
|||
48 STR_RELEASE_EXCESS_CAPACITY: "release_excess_capacity"
|
||||
49 STR_DROP_PREFIX: "drop_prefix"
|
||||
50 STR_DROP_SUFFIX: "drop_suffix"
|
||||
51 STR_WITH_ASCII_LOWERCASED: "with_ascii_lowercased"
|
||||
52 STR_WITH_ASCII_UPPERCASED: "with_ascii_uppercased"
|
||||
53 STR_CASELESS_ASCII_EQUALS: "caseless_ascii_equals"
|
||||
54 STR_FROM_UTF16: "from_utf16"
|
||||
55 STR_FROM_UTF16_LOSSY: "from_utf16_lossy"
|
||||
56 STR_FROM_UTF32: "from_utf32"
|
||||
57 STR_FROM_UTF32_LOSSY: "from_utf32_lossy"
|
||||
}
|
||||
6 LIST: "List" => {
|
||||
0 LIST_LIST: "List" exposed_apply_type=true // the List.List type alias
|
||||
|
|
|
@ -1549,6 +1549,9 @@ fn low_level_no_rc(lowlevel: &LowLevel) -> RC {
|
|||
ListPrepend => RC::Rc,
|
||||
StrJoinWith => RC::NoRc,
|
||||
ListSortWith => RC::Rc,
|
||||
StrWithAsciiLowercased => RC::Rc,
|
||||
StrWithAsciiUppercased => RC::Rc,
|
||||
StrCaselessAsciiEquals => RC::NoRc,
|
||||
|
||||
ListAppendUnsafe
|
||||
| ListReserve
|
||||
|
@ -1562,7 +1565,7 @@ fn low_level_no_rc(lowlevel: &LowLevel) -> RC {
|
|||
|
||||
Eq | NotEq => RC::NoRc,
|
||||
|
||||
And | Or | NumAdd | NumAddWrap | NumAddChecked | NumAddSaturated | NumSub | NumSubWrap
|
||||
NumAdd | NumAddWrap | NumAddChecked | NumAddSaturated | NumSub | NumSubWrap
|
||||
| NumSubChecked | NumSubSaturated | NumMul | NumMulWrap | NumMulSaturated
|
||||
| NumMulChecked | NumGt | NumGte | NumLt | NumLte | NumCompare | NumDivFrac
|
||||
| NumDivTruncUnchecked | NumDivCeilUnchecked | NumRemUnchecked | NumIsMultipleOf
|
||||
|
@ -1603,6 +1606,7 @@ fn low_level_no_rc(lowlevel: &LowLevel) -> RC {
|
|||
DictPseudoSeed => RC::NoRc,
|
||||
StrStartsWith | StrEndsWith => RC::NoRc,
|
||||
StrFromUtf8 => RC::Rc,
|
||||
StrFromUtf8Lossy => RC::Rc,
|
||||
StrToUtf8 => RC::Rc,
|
||||
StrRepeat => RC::NoRc,
|
||||
StrFromInt | StrFromFloat => RC::NoRc,
|
||||
|
|
|
@ -1258,10 +1258,13 @@ pub(crate) fn lowlevel_borrow_signature(op: LowLevel) -> &'static [Ownership] {
|
|||
StrReleaseExcessCapacity => &[OWNED],
|
||||
ListIncref => &[OWNED],
|
||||
ListDecref => &[OWNED],
|
||||
StrWithAsciiLowercased => &[OWNED],
|
||||
StrWithAsciiUppercased => &[OWNED],
|
||||
StrCaselessAsciiEquals => &[BORROWED, BORROWED],
|
||||
|
||||
Eq | NotEq => &[BORROWED, BORROWED],
|
||||
|
||||
And | Or | NumAdd | NumAddWrap | NumAddChecked | NumAddSaturated | NumSub | NumSubWrap
|
||||
NumAdd | NumAddWrap | NumAddChecked | NumAddSaturated | NumSub | NumSubWrap
|
||||
| NumSubChecked | NumSubSaturated | NumMul | NumMulWrap | NumMulSaturated
|
||||
| NumMulChecked | NumGt | NumGte | NumLt | NumLte | NumCompare | NumDivFrac
|
||||
| NumDivTruncUnchecked | NumDivCeilUnchecked | NumRemUnchecked | NumIsMultipleOf
|
||||
|
@ -1302,6 +1305,7 @@ pub(crate) fn lowlevel_borrow_signature(op: LowLevel) -> &'static [Ownership] {
|
|||
| NumF64FromParts => &[IRRELEVANT],
|
||||
StrStartsWith | StrEndsWith => &[BORROWED, BORROWED],
|
||||
StrFromUtf8 => &[OWNED],
|
||||
StrFromUtf8Lossy => &[BORROWED],
|
||||
StrToUtf8 => &[OWNED],
|
||||
StrRepeat => &[BORROWED, IRRELEVANT],
|
||||
StrFromInt | StrFromFloat => &[IRRELEVANT],
|
||||
|
|
|
@ -1241,7 +1241,13 @@ impl<'a> ReuseEnvironment<'a> {
|
|||
Retrieve the layout of a symbol.
|
||||
*/
|
||||
fn get_symbol_layout(&self, symbol: Symbol) -> &LayoutOption<'a> {
|
||||
self.symbol_layouts.get(&symbol).expect("Expected symbol to have a layout. It should have been inserted in the environment already.")
|
||||
self.symbol_layouts
|
||||
.get(&symbol)
|
||||
.expect(
|
||||
"Expected symbol to have a layout. \
|
||||
It should have been inserted in the environment already. \
|
||||
We are investigating this issue, follow github.com/roc-lang/roc/issues/7461 for updates.",
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -49,7 +49,15 @@ pub fn apply_trmc<'a, 'i>(
|
|||
|
||||
let env = &mut env;
|
||||
|
||||
for proc in procs.values_mut() {
|
||||
// TODO temporary workaround for #7531, remove this cloning and sorting once that is fixed
|
||||
let clone_procs = procs.clone();
|
||||
let mut procs_key_value_list = clone_procs.iter().collect::<std::vec::Vec<_>>();
|
||||
|
||||
procs_key_value_list.sort_by(|a, b| a.0 .0.cmp(&b.0 .0));
|
||||
|
||||
for (key, _) in procs_key_value_list {
|
||||
let proc = procs.get_mut(key).unwrap();
|
||||
|
||||
use self::SelfRecursive::*;
|
||||
if let SelfRecursive(id) = proc.is_self_recursive {
|
||||
let trmc_candidate_symbols = trmc_candidates(env.interner, proc);
|
||||
|
|
|
@ -738,7 +738,7 @@ fn parse_stmt_operator_chain<'a>(
|
|||
| Expr::Apply(
|
||||
Loc {
|
||||
region: _,
|
||||
value: Expr::Tag(..)
|
||||
value: Expr::Tag(_)
|
||||
},
|
||||
&[],
|
||||
_
|
||||
|
@ -1902,6 +1902,10 @@ fn parse_stmt_after_apply<'a>(
|
|||
) -> ParseResult<'a, Stmt<'a>, EExpr<'a>> {
|
||||
let before_op = state.clone();
|
||||
match loc(operator()).parse(arena, state.clone(), call_min_indent) {
|
||||
Err((MadeProgress, EExpr::BadOperator("|", _))) => {
|
||||
let expr = parse_expr_final(expr_state, arena);
|
||||
return Ok((MadeProgress, Stmt::Expr(expr), state));
|
||||
}
|
||||
Err((MadeProgress, f)) => Err((MadeProgress, f)),
|
||||
Ok((_, loc_op, state)) => {
|
||||
expr_state.consume_spaces(arena);
|
||||
|
@ -1930,43 +1934,6 @@ fn parse_stmt_after_apply<'a>(
|
|||
}
|
||||
}
|
||||
|
||||
// #[allow(clippy::too_many_arguments)]
|
||||
// fn parse_expr_after_apply<'a>(
|
||||
// arena: &'a Bump,
|
||||
// state: State<'a>,
|
||||
// min_indent: u32,
|
||||
// call_min_indent: u32,
|
||||
// check_for_arrow: CheckForArrow,
|
||||
// check_for_defs: bool,
|
||||
// mut expr_state: ExprState<'a>,
|
||||
// before_op: State<'a>,
|
||||
// initial_state: State<'a>,
|
||||
// ) -> Result<(Progress, Expr<'a>, State<'a>), (Progress, EExpr<'a>)> {
|
||||
// match loc(bin_op(check_for_defs)).parse(arena, state.clone(), call_min_indent) {
|
||||
// Err((MadeProgress, f)) => Err((MadeProgress, f)),
|
||||
// Ok((_, loc_op, state)) => {
|
||||
// expr_state.consume_spaces(arena);
|
||||
// let initial_state = before_op;
|
||||
// parse_expr_operator(
|
||||
// arena,
|
||||
// state,
|
||||
// min_indent,
|
||||
// call_min_indent,
|
||||
// options,
|
||||
// check_for_defs,
|
||||
// expr_state,
|
||||
// loc_op,
|
||||
// initial_state,
|
||||
// )
|
||||
// }
|
||||
// Err((NoProgress, _)) => {
|
||||
// let expr = parse_expr_final(expr_state, arena);
|
||||
// // roll back space parsing
|
||||
// Ok((MadeProgress, expr, initial_state))
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn parse_apply_arg<'a>(
|
||||
arena: &'a Bump,
|
||||
|
@ -2336,47 +2303,41 @@ pub fn parse_top_level_defs<'a>(
|
|||
|
||||
fn closure_help<'a>(check_for_arrow: CheckForArrow) -> impl Parser<'a, Expr<'a>, EClosure<'a>> {
|
||||
one_of!(
|
||||
closure_new_syntax_help(),
|
||||
closure_new_syntax_help(check_for_arrow),
|
||||
closure_old_syntax_help(check_for_arrow),
|
||||
)
|
||||
}
|
||||
|
||||
fn closure_new_syntax_help<'a>() -> impl Parser<'a, Expr<'a>, EClosure<'a>> {
|
||||
move |arena: &'a Bump, state: State<'a>, min_indent: u32| {
|
||||
let parser = map_with_arena(
|
||||
indented_seq_skip_first(
|
||||
error_on_pizza(byte_indent(b'|', EClosure::Bar), EClosure::Start),
|
||||
and(
|
||||
sep_by1_e(
|
||||
byte_indent(b',', EClosure::Comma),
|
||||
space0_around_ee(
|
||||
specialize_err(EClosure::Pattern, closure_param()),
|
||||
EClosure::IndentArg,
|
||||
EClosure::IndentArrow,
|
||||
),
|
||||
EClosure::Arg,
|
||||
),
|
||||
skip_first(
|
||||
// Parse the -> which separates params from body
|
||||
byte(b'|', EClosure::Bar),
|
||||
// Parse the body
|
||||
block(
|
||||
CheckForArrow(false),
|
||||
true,
|
||||
EClosure::IndentBody,
|
||||
EClosure::Body,
|
||||
),
|
||||
fn closure_new_syntax_help<'a>(
|
||||
check_for_arrow: CheckForArrow,
|
||||
) -> impl Parser<'a, Expr<'a>, EClosure<'a>> {
|
||||
map_with_arena(
|
||||
skip_first(
|
||||
error_on_pizza(byte_indent(b'|', EClosure::Bar), EClosure::Start),
|
||||
reset_min_indent(and(
|
||||
sep_by1_e(
|
||||
byte_indent(b',', EClosure::Comma),
|
||||
space0_around_ee(
|
||||
specialize_err(EClosure::Pattern, closure_param()),
|
||||
EClosure::IndentArg,
|
||||
EClosure::IndentArrow,
|
||||
),
|
||||
EClosure::Arg,
|
||||
),
|
||||
),
|
||||
|arena: &'a Bump, (params, body)| {
|
||||
let params: Vec<'a, Loc<Pattern<'a>>> = params;
|
||||
let params: &'a [Loc<Pattern<'a>>] = params.into_bump_slice();
|
||||
Expr::Closure(params, arena.alloc(body))
|
||||
},
|
||||
);
|
||||
parser.parse(arena, state, min_indent)
|
||||
}
|
||||
skip_first(
|
||||
// Parse the -> which separates params from body
|
||||
byte(b'|', EClosure::Bar),
|
||||
// Parse the body
|
||||
block(check_for_arrow, true, EClosure::IndentBody, EClosure::Body),
|
||||
),
|
||||
)),
|
||||
),
|
||||
|arena: &'a Bump, (params, body)| {
|
||||
let params: Vec<'a, Loc<Pattern<'a>>> = params;
|
||||
let params: &'a [Loc<Pattern<'a>>] = params.into_bump_slice();
|
||||
Expr::Closure(params, arena.alloc(body))
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
fn closure_old_syntax_help<'a>(
|
||||
|
@ -2385,12 +2346,12 @@ fn closure_old_syntax_help<'a>(
|
|||
// closure_help_help(options)
|
||||
map_with_arena(
|
||||
// After the first token, all other tokens must be indented past the start of the line
|
||||
indented_seq_skip_first(
|
||||
skip_first(
|
||||
// All closures start with a '\' - e.g. (\x -> x + 1)
|
||||
byte_indent(b'\\', EClosure::Start),
|
||||
// Once we see the '\', we're committed to parsing this as a closure.
|
||||
// It may turn out to be malformed, but it is definitely a closure.
|
||||
and(
|
||||
reset_min_indent(and(
|
||||
// Parse the params
|
||||
// Params are comma-separated
|
||||
sep_by1_e(
|
||||
|
@ -2408,7 +2369,7 @@ fn closure_old_syntax_help<'a>(
|
|||
// Parse the body
|
||||
block(check_for_arrow, true, EClosure::IndentBody, EClosure::Body),
|
||||
),
|
||||
),
|
||||
)),
|
||||
),
|
||||
|arena: &'a Bump, (params, body)| {
|
||||
let params: Vec<'a, Loc<Pattern<'a>>> = params;
|
||||
|
@ -3073,6 +3034,11 @@ fn parse_stmt_seq<'a, E: SpaceProblem + 'a>(
|
|||
break;
|
||||
}
|
||||
|
||||
if new_state.bytes().starts_with(b"|") {
|
||||
state = state_before_space;
|
||||
break;
|
||||
}
|
||||
|
||||
return Err((
|
||||
MadeProgress,
|
||||
wrap_error(arena.alloc(EExpr::BadExprEnd(state.pos())), state.pos()),
|
||||
|
@ -3424,7 +3390,7 @@ fn starts_with_spaces_conservative(value: &Pattern<'_>) -> bool {
|
|||
}
|
||||
|
||||
fn type_header_equivalent_to_pat<'a>(header: &TypeHeader<'a>, pat: &Pattern<'a>) -> bool {
|
||||
match pat {
|
||||
match pat.without_spaces() {
|
||||
Pattern::Apply(func, args) => {
|
||||
if !matches!(func.value, Pattern::Tag(tag) if header.name.value == tag) {
|
||||
return false;
|
||||
|
@ -3433,7 +3399,7 @@ fn type_header_equivalent_to_pat<'a>(header: &TypeHeader<'a>, pat: &Pattern<'a>)
|
|||
return false;
|
||||
}
|
||||
for (arg, var) in (*args).iter().zip(header.vars) {
|
||||
match (arg.value, var.value) {
|
||||
match (arg.value.without_spaces(), var.value.without_spaces()) {
|
||||
(Pattern::Identifier { ident: left }, TypeVar::Identifier(right)) => {
|
||||
if left != right {
|
||||
return false;
|
||||
|
@ -3444,7 +3410,7 @@ fn type_header_equivalent_to_pat<'a>(header: &TypeHeader<'a>, pat: &Pattern<'a>)
|
|||
}
|
||||
true
|
||||
}
|
||||
Pattern::Tag(tag) => header.vars.is_empty() && header.name.value == *tag,
|
||||
Pattern::Tag(tag) => header.vars.is_empty() && header.name.value == tag,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
@ -4025,9 +3991,10 @@ enum OperatorOrDef {
|
|||
}
|
||||
|
||||
fn bin_op<'a>(check_for_defs: bool) -> impl Parser<'a, BinOp, EExpr<'a>> {
|
||||
move |_, state: State<'a>, min_indent| {
|
||||
(move |arena: &'a Bump, state: State<'a>, min_indent| {
|
||||
let start = state.pos();
|
||||
let (_, op, state) = operator_help(EExpr::Start, EExpr::BadOperator, state, min_indent)?;
|
||||
let (_, op, state) =
|
||||
operator_help(arena, EExpr::Start, EExpr::BadOperator, state, min_indent)?;
|
||||
let err_progress = if check_for_defs {
|
||||
MadeProgress
|
||||
} else {
|
||||
|
@ -4043,16 +4010,20 @@ fn bin_op<'a>(check_for_defs: bool) -> impl Parser<'a, BinOp, EExpr<'a>> {
|
|||
Err((err_progress, EExpr::BadOperator(":=", start)))
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
.trace("bin_op")
|
||||
}
|
||||
|
||||
fn operator<'a>() -> impl Parser<'a, OperatorOrDef, EExpr<'a>> {
|
||||
(move |_, state, min_indent| operator_help(EExpr::Start, EExpr::BadOperator, state, min_indent))
|
||||
.trace("operator")
|
||||
(move |arena: &'a Bump, state, min_indent| {
|
||||
operator_help(arena, EExpr::Start, EExpr::BadOperator, state, min_indent)
|
||||
})
|
||||
.trace("operator")
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn operator_help<'a, F, G, E>(
|
||||
arena: &'a Bump,
|
||||
to_expectation: F,
|
||||
to_error: G,
|
||||
mut state: State<'a>,
|
||||
|
@ -4063,6 +4034,21 @@ where
|
|||
G: Fn(&'a str, Position) -> E,
|
||||
E: 'a,
|
||||
{
|
||||
let and_or = either(
|
||||
parser::keyword(keyword::AND, EExpr::End),
|
||||
parser::keyword(keyword::OR, EExpr::End),
|
||||
);
|
||||
|
||||
match and_or.parse(arena, state.clone(), min_indent) {
|
||||
Ok((MadeProgress, Either::First(_), state)) => {
|
||||
return Ok((MadeProgress, OperatorOrDef::BinOp(BinOp::And), state))
|
||||
}
|
||||
Ok((MadeProgress, Either::Second(_), state)) => {
|
||||
return Ok((MadeProgress, OperatorOrDef::BinOp(BinOp::Or), state))
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
let chomped = chomp_ops(state.bytes());
|
||||
|
||||
macro_rules! good {
|
||||
|
@ -4097,6 +4083,7 @@ where
|
|||
|
||||
good!(OperatorOrDef::BinOp(BinOp::Minus), 1)
|
||||
}
|
||||
"?" => good!(OperatorOrDef::BinOp(BinOp::SingleQuestion), 1),
|
||||
"*" => good!(OperatorOrDef::BinOp(BinOp::Star), 1),
|
||||
"/" => good!(OperatorOrDef::BinOp(BinOp::Slash), 1),
|
||||
"%" => good!(OperatorOrDef::BinOp(BinOp::Percent), 1),
|
||||
|
@ -4118,6 +4105,7 @@ where
|
|||
"<=" => good!(OperatorOrDef::BinOp(BinOp::LessThanOrEq), 2),
|
||||
"&&" => good!(OperatorOrDef::BinOp(BinOp::And), 2),
|
||||
"||" => good!(OperatorOrDef::BinOp(BinOp::Or), 2),
|
||||
"|" => Err((NoProgress, to_error("|", state.pos()))),
|
||||
"//" => good!(OperatorOrDef::BinOp(BinOp::DoubleSlash), 2),
|
||||
"->" => {
|
||||
// makes no progress, so it does not interfere with `_ if isGood -> ...`
|
||||
|
|
|
@ -927,7 +927,7 @@ impl<'a> HeaderType<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum HeaderType<'a> {
|
||||
App {
|
||||
provides: &'a [Loc<ExposedName<'a>>],
|
||||
|
|
|
@ -10,6 +10,8 @@ pub const IMPORT: &str = "import";
|
|||
pub const EXPECT: &str = "expect";
|
||||
pub const RETURN: &str = "return";
|
||||
pub const CRASH: &str = "crash";
|
||||
pub const AND: &str = "and";
|
||||
pub const OR: &str = "or";
|
||||
|
||||
// These keywords are valid in imports
|
||||
pub const EXPOSING: &str = "exposing";
|
||||
|
@ -21,8 +23,8 @@ pub const WHERE: &str = "where";
|
|||
// These keywords are valid in headers
|
||||
pub const PLATFORM: &str = "platform";
|
||||
|
||||
pub const KEYWORDS: [&str; 11] = [
|
||||
IF, THEN, ELSE, WHEN, AS, IS, DBG, IMPORT, EXPECT, RETURN, CRASH,
|
||||
pub const KEYWORDS: [&str; 13] = [
|
||||
IF, THEN, ELSE, WHEN, AS, IS, DBG, IMPORT, EXPECT, RETURN, CRASH, AND, OR,
|
||||
];
|
||||
|
||||
pub fn is_allowed_identifier(mut ident: &str) -> bool {
|
||||
|
|
|
@ -778,11 +778,11 @@ impl<'a> Normalize<'a> for Expr<'a> {
|
|||
Expr::If {
|
||||
if_thens,
|
||||
final_else,
|
||||
indented_else,
|
||||
indented_else: _,
|
||||
} => Expr::If {
|
||||
if_thens: if_thens.normalize(arena),
|
||||
final_else: arena.alloc(final_else.normalize(arena)),
|
||||
indented_else,
|
||||
indented_else: false,
|
||||
},
|
||||
Expr::When(a, b) => Expr::When(arena.alloc(a.normalize(arena)), b.normalize(arena)),
|
||||
Expr::ParensAround(a) => {
|
||||
|
|
|
@ -15,15 +15,12 @@ use bumpalo::Bump;
|
|||
use roc_can::abilities::{AbilitiesStore, MemberSpecializationInfo};
|
||||
use roc_can::constraint::Constraint::{self, *};
|
||||
use roc_can::constraint::{
|
||||
Cycle, FxCallConstraint, FxSuffixConstraint, FxSuffixKind, LetConstraint, OpportunisticResolve,
|
||||
TryTargetConstraint,
|
||||
Cycle, FxCallConstraint, FxSuffixConstraint, FxSuffixKind, Generalizable, LetConstraint,
|
||||
OpportunisticResolve, TryTargetConstraint,
|
||||
};
|
||||
use roc_can::expected::{Expected, PExpected};
|
||||
use roc_can::module::ModuleParams;
|
||||
use roc_collections::{VecMap, VecSet};
|
||||
use roc_debug_flags::dbg_do;
|
||||
#[cfg(debug_assertions)]
|
||||
use roc_debug_flags::ROC_VERIFY_RIGID_LET_GENERALIZED;
|
||||
use roc_error_macros::internal_error;
|
||||
use roc_module::ident::IdentSuffix;
|
||||
use roc_module::symbol::{ModuleId, Symbol};
|
||||
|
@ -32,8 +29,8 @@ use roc_region::all::{Loc, Region};
|
|||
use roc_solve_problem::TypeError;
|
||||
use roc_solve_schema::UnificationMode;
|
||||
use roc_types::subs::{
|
||||
self, Content, FlatType, GetSubsSlice, Mark, OptVariable, Rank, Subs, TagExt, UlsOfVar,
|
||||
Variable,
|
||||
self, Content, ErrorTypeContext, FlatType, GetSubsSlice, Mark, OptVariable, Rank, Subs, TagExt,
|
||||
UlsOfVar, Variable,
|
||||
};
|
||||
use roc_types::types::{Category, Polarity, Reason, RecordField, Type, TypeExtension, Types, Uls};
|
||||
use roc_unify::unify::{
|
||||
|
@ -356,29 +353,13 @@ fn solve(
|
|||
generalize(env, young_mark, visit_mark, rank.next());
|
||||
debug_assert!(env.pools.get(rank.next()).is_empty(), "variables left over in let-binding scope, but they should all be in a lower scope or generalized now");
|
||||
|
||||
// check that things went well
|
||||
dbg_do!(ROC_VERIFY_RIGID_LET_GENERALIZED, {
|
||||
let rigid_vars = &env.constraints[let_con.rigid_vars];
|
||||
|
||||
// NOTE the `subs.redundant` check does not come from elm.
|
||||
// It's unclear whether this is a bug with our implementation
|
||||
// (something is redundant that shouldn't be)
|
||||
// or that it just never came up in elm.
|
||||
let mut it = rigid_vars
|
||||
.iter()
|
||||
.filter(|loc_var| {
|
||||
let var = loc_var.value;
|
||||
!env.subs.redundant(var) && env.subs.get_rank(var) != Rank::GENERALIZED
|
||||
})
|
||||
.peekable();
|
||||
|
||||
if it.peek().is_some() {
|
||||
let failing: Vec<_> = it.collect();
|
||||
println!("Rigids {:?}", &rigid_vars);
|
||||
println!("Failing {failing:?}");
|
||||
debug_assert!(false);
|
||||
}
|
||||
});
|
||||
let named_variables = &env.constraints[let_con.rigid_vars];
|
||||
check_named_variables_are_generalized(
|
||||
env,
|
||||
problems,
|
||||
named_variables,
|
||||
let_con.generalizable,
|
||||
);
|
||||
|
||||
let mut new_scope = scope.clone();
|
||||
for (symbol, loc_var) in local_def_vars.iter() {
|
||||
|
@ -1636,6 +1617,30 @@ fn solve(
|
|||
state
|
||||
}
|
||||
|
||||
fn check_named_variables_are_generalized(
|
||||
env: &mut InferenceEnv<'_>,
|
||||
problems: &mut Vec<TypeError>,
|
||||
named_variables: &[Loc<Variable>],
|
||||
generalizable: Generalizable,
|
||||
) {
|
||||
for loc_var in named_variables {
|
||||
let is_generalized = env.subs.get_rank(loc_var.value) == Rank::GENERALIZED;
|
||||
if !is_generalized {
|
||||
// TODO: should be OF_PATTERN if on the LHS of a function, otherwise OF_VALUE.
|
||||
let polarity = Polarity::OF_VALUE;
|
||||
let ctx = ErrorTypeContext::NON_GENERALIZED_AS_INFERRED;
|
||||
let error_type = env
|
||||
.subs
|
||||
.var_to_error_type_contextual(loc_var.value, ctx, polarity);
|
||||
problems.push(TypeError::TypeIsNotGeneralized(
|
||||
loc_var.region,
|
||||
error_type,
|
||||
generalizable,
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn solve_suffix_fx(
|
||||
env: &mut InferenceEnv<'_>,
|
||||
problems: &mut Vec<TypeError>,
|
||||
|
|
|
@ -165,7 +165,7 @@ mod solve_expr {
|
|||
Str.from_utf8
|
||||
"
|
||||
),
|
||||
"List U8 -> Result Str [BadUtf8 { index : U64, problem : Utf8ByteProblem }]",
|
||||
"List U8 -> Result Str [BadUtf8 { index : U64, problem : Utf8Problem }]",
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -2510,13 +2510,15 @@ mod solve_expr {
|
|||
infer_eq_without_problem(
|
||||
indoc!(
|
||||
r"
|
||||
empty : [Cons a (ConsList a), Nil] as ConsList a
|
||||
empty = Nil
|
||||
ConsList a : [Cons a (ConsList a), Nil]
|
||||
|
||||
empty
|
||||
"
|
||||
empty : ConsList _
|
||||
empty = Nil
|
||||
|
||||
empty
|
||||
"
|
||||
),
|
||||
"ConsList a",
|
||||
"ConsList *",
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -3742,7 +3744,7 @@ mod solve_expr {
|
|||
indoc!(
|
||||
r"
|
||||
\rec ->
|
||||
{ x, y } : { x : I64, y ? Bool }*
|
||||
{ x, y } : { x : I64, y ? Bool }_
|
||||
{ x, y ? Bool.false } = rec
|
||||
|
||||
{ x, y }
|
||||
|
@ -3824,6 +3826,42 @@ mod solve_expr {
|
|||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn str_with_ascii_lowercased() {
|
||||
infer_eq_without_problem(
|
||||
indoc!(
|
||||
r"
|
||||
Str.with_ascii_lowercased
|
||||
"
|
||||
),
|
||||
"Str -> Str",
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn str_with_ascii_uppercased() {
|
||||
infer_eq_without_problem(
|
||||
indoc!(
|
||||
r"
|
||||
Str.with_ascii_uppercased
|
||||
"
|
||||
),
|
||||
"Str -> Str",
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn str_caseless_ascii_equals() {
|
||||
infer_eq_without_problem(
|
||||
indoc!(
|
||||
r"
|
||||
Str.caseless_ascii_equals
|
||||
"
|
||||
),
|
||||
"Str, Str -> Bool",
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn list_take_first() {
|
||||
infer_eq_without_problem(
|
||||
|
@ -3909,26 +3947,6 @@ mod solve_expr {
|
|||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn double_named_rigids() {
|
||||
infer_eq_without_problem(
|
||||
indoc!(
|
||||
r#"
|
||||
app "test" provides [main] to "./platform"
|
||||
|
||||
|
||||
main : List x
|
||||
main =
|
||||
empty : List x
|
||||
empty = []
|
||||
|
||||
empty
|
||||
"#
|
||||
),
|
||||
"List x",
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn double_tag_application() {
|
||||
infer_eq_without_problem(
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
//! Provides types to describe problems that can occur during solving.
|
||||
use std::{path::PathBuf, str::Utf8Error};
|
||||
|
||||
use roc_can::constraint::{ExpectEffectfulReason, FxSuffixKind};
|
||||
use roc_can::constraint::{ExpectEffectfulReason, FxSuffixKind, Generalizable};
|
||||
use roc_can::expr::TryKind;
|
||||
use roc_can::{
|
||||
constraint::FxCallKind,
|
||||
|
@ -50,6 +50,7 @@ pub enum TypeError {
|
|||
UnsuffixedEffectfulFunction(Region, FxSuffixKind),
|
||||
SuffixedPureFunction(Region, FxSuffixKind),
|
||||
InvalidTryTarget(Region, ErrorType, TryKind),
|
||||
TypeIsNotGeneralized(Region, ErrorType, Generalizable),
|
||||
}
|
||||
|
||||
impl TypeError {
|
||||
|
@ -80,6 +81,7 @@ impl TypeError {
|
|||
TypeError::UnsuffixedEffectfulFunction(_, _) => Warning,
|
||||
TypeError::SuffixedPureFunction(_, _) => Warning,
|
||||
TypeError::InvalidTryTarget(_, _, _) => RuntimeError,
|
||||
TypeError::TypeIsNotGeneralized(..) => RuntimeError,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -101,7 +103,8 @@ impl TypeError {
|
|||
| TypeError::ExpectedEffectful(region, _)
|
||||
| TypeError::UnsuffixedEffectfulFunction(region, _)
|
||||
| TypeError::SuffixedPureFunction(region, _)
|
||||
| TypeError::InvalidTryTarget(region, _, _) => Some(*region),
|
||||
| TypeError::InvalidTryTarget(region, _, _)
|
||||
| TypeError::TypeIsNotGeneralized(region, _, _) => Some(*region),
|
||||
TypeError::UnfulfilledAbility(ab, ..) => ab.region(),
|
||||
TypeError::Exhaustive(e) => Some(e.region()),
|
||||
TypeError::CircularDef(c) => c.first().map(|ce| ce.symbol_region),
|
||||
|
|
|
@ -2095,13 +2095,13 @@ mod eq {
|
|||
|
||||
LyingEq := U8 implements [Eq {is_eq}]
|
||||
|
||||
is_eq = \@LyingEq m, @LyingEq n -> m != n
|
||||
is_eq = \@LyingEq(m), @LyingEq(n) -> m != n
|
||||
|
||||
main =
|
||||
a = @LyingEq 10
|
||||
b = @LyingEq 5
|
||||
c = @LyingEq 5
|
||||
if Bool.is_eq a b && !(Bool.is_eq b c) then
|
||||
a = @LyingEq(10)
|
||||
b = @LyingEq(5)
|
||||
c = @LyingEq(5)
|
||||
if Bool.is_eq(a, b) and !(Bool.is_eq(b, c)) then
|
||||
"okay"
|
||||
else
|
||||
"fail"
|
||||
|
|
|
@ -121,7 +121,7 @@ fn bool_logic() {
|
|||
bool2 = Bool.false
|
||||
bool3 = !bool1
|
||||
|
||||
(bool1 && bool2) || bool2 && bool3
|
||||
(bool1 and bool2) or bool2 and bool3
|
||||
"#
|
||||
),
|
||||
false,
|
||||
|
@ -132,19 +132,19 @@ fn bool_logic() {
|
|||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm", feature = "gen-dev"))]
|
||||
fn and_bool() {
|
||||
assert_evals_to!("Bool.true && Bool.true", true, bool);
|
||||
assert_evals_to!("Bool.true && Bool.false", false, bool);
|
||||
assert_evals_to!("Bool.false && Bool.true", false, bool);
|
||||
assert_evals_to!("Bool.false && Bool.false", false, bool);
|
||||
assert_evals_to!("Bool.true and Bool.true", true, bool);
|
||||
assert_evals_to!("Bool.true and Bool.false", false, bool);
|
||||
assert_evals_to!("Bool.false and Bool.true", false, bool);
|
||||
assert_evals_to!("Bool.false and Bool.false", false, bool);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm", feature = "gen-dev"))]
|
||||
fn or_bool() {
|
||||
assert_evals_to!("Bool.true || Bool.true", true, bool);
|
||||
assert_evals_to!("Bool.true || Bool.false", true, bool);
|
||||
assert_evals_to!("Bool.false || Bool.true", true, bool);
|
||||
assert_evals_to!("Bool.false || Bool.false", false, bool);
|
||||
assert_evals_to!("Bool.true or Bool.true", true, bool);
|
||||
assert_evals_to!("Bool.true or Bool.false", true, bool);
|
||||
assert_evals_to!("Bool.false or Bool.true", true, bool);
|
||||
assert_evals_to!("Bool.false or Bool.false", false, bool);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -544,7 +544,7 @@ fn eq_different_rosetrees() {
|
|||
|
||||
cd = c2 == d2
|
||||
|
||||
ab && cd
|
||||
ab and cd
|
||||
"#
|
||||
),
|
||||
true,
|
||||
|
|
|
@ -662,7 +662,7 @@ fn linked_list_len_1() {
|
|||
|
||||
LinkedList a : [Nil, Cons a (LinkedList a)]
|
||||
|
||||
one : LinkedList (Int *)
|
||||
one : LinkedList (Int _)
|
||||
one = Cons 1 Nil
|
||||
|
||||
length : LinkedList a -> Int *
|
||||
|
@ -690,7 +690,7 @@ fn linked_list_len_twice_1() {
|
|||
|
||||
LinkedList a : [Nil, Cons a (LinkedList a)]
|
||||
|
||||
one : LinkedList (Int *)
|
||||
one : LinkedList (Int _)
|
||||
one = Cons 1 Nil
|
||||
|
||||
length : LinkedList a -> Int *
|
||||
|
@ -718,7 +718,7 @@ fn linked_list_len_3() {
|
|||
|
||||
LinkedList a : [Nil, Cons a (LinkedList a)]
|
||||
|
||||
three : LinkedList (Int *)
|
||||
three : LinkedList (Int _)
|
||||
three = Cons 3 (Cons 2 (Cons 1 Nil))
|
||||
|
||||
length : LinkedList a -> Int *
|
||||
|
@ -747,7 +747,7 @@ fn linked_list_sum_num_a() {
|
|||
|
||||
LinkedList a : [Nil, Cons a (LinkedList a)]
|
||||
|
||||
three : LinkedList (Int *)
|
||||
three : LinkedList (Int _)
|
||||
three = Cons 3 (Cons 2 (Cons 1 Nil))
|
||||
|
||||
|
||||
|
@ -776,7 +776,7 @@ fn linked_list_sum_int() {
|
|||
|
||||
LinkedList a : [Nil, Cons a (LinkedList a)]
|
||||
|
||||
zero : LinkedList (Int *)
|
||||
zero : LinkedList (Int _)
|
||||
zero = Nil
|
||||
|
||||
sum : LinkedList (Int a) -> Int a
|
||||
|
@ -804,7 +804,7 @@ fn linked_list_map() {
|
|||
|
||||
LinkedList a : [Nil, Cons a (LinkedList a)]
|
||||
|
||||
three : LinkedList (Int *)
|
||||
three : LinkedList (Int _)
|
||||
three = Cons 3 (Cons 2 (Cons 1 Nil))
|
||||
|
||||
sum : LinkedList (Num a) -> Num a
|
||||
|
@ -836,7 +836,7 @@ fn when_nested_maybe() {
|
|||
r"
|
||||
Maybe a : [Nothing, Just a]
|
||||
|
||||
x : Maybe (Maybe (Int a))
|
||||
x : Maybe (Maybe (Int _))
|
||||
x = Just (Just 41)
|
||||
|
||||
when x is
|
||||
|
@ -853,7 +853,7 @@ fn when_nested_maybe() {
|
|||
r"
|
||||
Maybe a : [Nothing, Just a]
|
||||
|
||||
x : Maybe (Maybe (Int *))
|
||||
x : Maybe (Maybe (Int _))
|
||||
x = Just Nothing
|
||||
|
||||
when x is
|
||||
|
@ -871,7 +871,7 @@ fn when_nested_maybe() {
|
|||
r"
|
||||
Maybe a : [Nothing, Just a]
|
||||
|
||||
x : Maybe (Maybe (Int *))
|
||||
x : Maybe (Maybe (Int _))
|
||||
x = Nothing
|
||||
|
||||
when x is
|
||||
|
@ -1402,7 +1402,7 @@ fn recursive_function_with_rigid() {
|
|||
else
|
||||
1 + foo { count: state.count - 1, x: state.x }
|
||||
|
||||
main : Int *
|
||||
main : Int _
|
||||
main =
|
||||
foo { count: 3, x: {} }
|
||||
"#
|
||||
|
@ -1517,7 +1517,7 @@ fn rbtree_balance_3() {
|
|||
balance = \key, left ->
|
||||
Node key left Empty
|
||||
|
||||
main : RedBlackTree (Int *)
|
||||
main : RedBlackTree (Int _)
|
||||
main =
|
||||
balance 0 Empty
|
||||
"#
|
||||
|
@ -1696,7 +1696,7 @@ fn nested_pattern_match_two_ways() {
|
|||
_ -> 3
|
||||
_ -> 3
|
||||
|
||||
main : Int *
|
||||
main : Int _
|
||||
main =
|
||||
when balance Nil is
|
||||
_ -> 3
|
||||
|
@ -1719,7 +1719,7 @@ fn nested_pattern_match_two_ways() {
|
|||
Cons 1 (Cons 1 _) -> 3
|
||||
_ -> 3
|
||||
|
||||
main : Int *
|
||||
main : Int _
|
||||
main =
|
||||
when balance Nil is
|
||||
_ -> 3
|
||||
|
@ -1751,7 +1751,7 @@ fn linked_list_guarded_double_pattern_match() {
|
|||
_ -> 3
|
||||
_ -> 3
|
||||
|
||||
main : Int *
|
||||
main : Int _
|
||||
main =
|
||||
when balance Nil is
|
||||
_ -> 3
|
||||
|
@ -1778,7 +1778,7 @@ fn linked_list_double_pattern_match() {
|
|||
Cons _ (Cons x _) -> x
|
||||
_ -> 0
|
||||
|
||||
main : Int *
|
||||
main : Int _
|
||||
main =
|
||||
foo (Cons 1 (Cons 32 Nil))
|
||||
"#
|
||||
|
@ -1886,7 +1886,7 @@ fn wildcard_rigid() {
|
|||
@Effect inner
|
||||
|
||||
|
||||
main : MyTask {} (Frac *)
|
||||
main : MyTask {} (Frac _)
|
||||
main = always {}
|
||||
"#
|
||||
),
|
||||
|
|
|
@ -135,7 +135,7 @@ fn err_type_var_annotation() {
|
|||
assert_evals_to!(
|
||||
indoc!(
|
||||
r"
|
||||
ok : Result I64 *
|
||||
ok : Result I64 _
|
||||
ok = Ok 3
|
||||
|
||||
Result.map_ok ok (\x -> x + 1)
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -158,19 +158,19 @@ fn even_odd() {
|
|||
assert_evals_to!(
|
||||
indoc!(
|
||||
r"
|
||||
even = \n ->
|
||||
even = |n|
|
||||
when n is
|
||||
0 -> Bool.true
|
||||
1 -> Bool.false
|
||||
_ -> odd (n - 1)
|
||||
_ -> odd(n - 1)
|
||||
|
||||
odd = \n ->
|
||||
odd = |n|
|
||||
when n is
|
||||
0 -> Bool.false
|
||||
1 -> Bool.true
|
||||
_ -> even (n - 1)
|
||||
_ -> even(n - 1)
|
||||
|
||||
odd 5 && even 42
|
||||
odd(5) and even(42)
|
||||
"
|
||||
),
|
||||
true,
|
||||
|
@ -1075,7 +1075,7 @@ fn applied_tag_function_result() {
|
|||
assert_evals_to!(
|
||||
indoc!(
|
||||
r#"
|
||||
x : List (Result Str *)
|
||||
x : List (Result Str _)
|
||||
x = List.map ["a", "b"] Ok
|
||||
|
||||
List.keep_oks x (\y -> y)
|
||||
|
@ -2315,12 +2315,12 @@ fn recursive_tag_id_in_allocation_eq() {
|
|||
]
|
||||
|
||||
x : Value
|
||||
x = G 42
|
||||
x = G(42)
|
||||
|
||||
y : Value
|
||||
y = H 42
|
||||
y = H(42)
|
||||
|
||||
main = (x == x) && (x != y) && (y == y)
|
||||
main = x == x and x != y and y == y
|
||||
"#
|
||||
),
|
||||
true,
|
||||
|
|
|
@ -22,7 +22,6 @@ pub mod gen_str;
|
|||
pub mod gen_tags;
|
||||
pub mod gen_tuples;
|
||||
mod helpers;
|
||||
pub mod wasm_str;
|
||||
|
||||
#[cfg(feature = "gen-wasm")]
|
||||
pub mod wasm_linking;
|
||||
|
|
|
@ -66,7 +66,7 @@ fn build_app_mono<'a>(
|
|||
|
||||
let or1_expr = Expr::Call(Call {
|
||||
call_type: CallType::LowLevel {
|
||||
op: LowLevel::Or,
|
||||
op: LowLevel::NumBitwiseOr,
|
||||
update_mode: UpdateModeId::BACKEND_DUMMY,
|
||||
},
|
||||
arguments: arena.alloc([js_call_result, host_call_result]),
|
||||
|
@ -74,7 +74,7 @@ fn build_app_mono<'a>(
|
|||
|
||||
let or2_expr = Expr::Call(Call {
|
||||
call_type: CallType::LowLevel {
|
||||
op: LowLevel::Or,
|
||||
op: LowLevel::NumBitwiseOr,
|
||||
update_mode: UpdateModeId::BACKEND_DUMMY,
|
||||
},
|
||||
arguments: arena.alloc([or1, bitflag]),
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,6 +1,6 @@
|
|||
procedure Bool.11 (#Attr.2, #Attr.3):
|
||||
let Bool.23 : Int1 = lowlevel Eq #Attr.2 #Attr.3;
|
||||
ret Bool.23;
|
||||
procedure Bool.9 (#Attr.2, #Attr.3):
|
||||
let Bool.21 : Int1 = lowlevel Eq #Attr.2 #Attr.3;
|
||||
ret Bool.21;
|
||||
|
||||
procedure List.116 (List.563, List.564, List.565):
|
||||
let List.693 : U64 = 0i64;
|
||||
|
@ -51,7 +51,7 @@ procedure List.72 (#Attr.2, #Attr.3, #Attr.4):
|
|||
let List.681 : List U8 = lowlevel ListSublist #Attr.2 #Attr.3 #Attr.4;
|
||||
ret List.681;
|
||||
|
||||
procedure List.80 (#Derived_gen.0, #Derived_gen.1, #Derived_gen.2, #Derived_gen.3, #Derived_gen.4):
|
||||
procedure List.80 (Bool.22, Bool.23, Bool.24, Bool.25, Bool.26):
|
||||
joinpoint List.695 List.566 List.567 List.568 List.569 List.570:
|
||||
let List.697 : Int1 = CallByName Num.22 List.569 List.570;
|
||||
if List.697 then
|
||||
|
@ -75,8 +75,8 @@ procedure List.80 (#Derived_gen.0, #Derived_gen.1, #Derived_gen.2, #Derived_gen.
|
|||
let List.696 : [C U64, C U64] = TagId(1) List.567;
|
||||
ret List.696;
|
||||
in
|
||||
inc #Derived_gen.0;
|
||||
jump List.695 #Derived_gen.0 #Derived_gen.1 #Derived_gen.2 #Derived_gen.3 #Derived_gen.4;
|
||||
inc Bool.22;
|
||||
jump List.695 Bool.22 Bool.23 Bool.24 Bool.25 Bool.26;
|
||||
|
||||
procedure Num.22 (#Attr.2, #Attr.3):
|
||||
let Num.286 : Int1 = lowlevel NumLt #Attr.2 #Attr.3;
|
||||
|
@ -95,7 +95,7 @@ procedure Test.1 (Test.2):
|
|||
let Test.14 : {} = Struct {};
|
||||
let Test.3 : U64 = CallByName List.26 Test.2 Test.13 Test.14;
|
||||
let Test.12 : U64 = 0i64;
|
||||
let Test.10 : Int1 = CallByName Bool.11 Test.3 Test.12;
|
||||
let Test.10 : Int1 = CallByName Bool.9 Test.3 Test.12;
|
||||
if Test.10 then
|
||||
ret Test.2;
|
||||
else
|
||||
|
|
|
@ -8,7 +8,7 @@ procedure Test.4 (Test.27):
|
|||
let Test.38 : I64 = CallByName Test.5 Test.27 Test.39 Test.40;
|
||||
ret Test.38;
|
||||
|
||||
procedure Test.5 (#Derived_gen.0, #Derived_gen.1, #Derived_gen.2):
|
||||
procedure Test.5 (Bool.21, Bool.22, Bool.23):
|
||||
joinpoint Test.41 Test.29 Test.30 Test.31:
|
||||
let Test.51 : U8 = 0i64;
|
||||
let Test.52 : U8 = GetTagId Test.29;
|
||||
|
@ -16,22 +16,22 @@ procedure Test.5 (#Derived_gen.0, #Derived_gen.1, #Derived_gen.2):
|
|||
if Test.53 then
|
||||
let Test.32 : [<rnu><null>, C *self *self] = UnionAtIndex (Id 0) (Index 0) Test.29;
|
||||
let Test.33 : [<rnu><null>, C *self *self] = UnionAtIndex (Id 0) (Index 1) Test.29;
|
||||
joinpoint #Derived_gen.3 #Derived_gen.6:
|
||||
let #Derived_gen.7 : [<rnu>C [<rnu><null>, C *self *self] *self, <null>] = lowlevel PtrCast #Derived_gen.6;
|
||||
let Test.43 : [<rnu>C [<rnu><null>, C *self *self] *self, <null>] = Reuse #Derived_gen.7 UpdateModeId { id: 1 } TagId(1) Test.33 Test.30;
|
||||
joinpoint Bool.24 Bool.27:
|
||||
let Bool.28 : [<rnu>C [<rnu><null>, C *self *self] *self, <null>] = lowlevel PtrCast Bool.27;
|
||||
let Test.43 : [<rnu>C [<rnu><null>, C *self *self] *self, <null>] = Reuse Bool.28 UpdateModeId { id: 1 } TagId(1) Test.33 Test.30;
|
||||
let Test.45 : I64 = 1i64;
|
||||
let Test.44 : I64 = CallByName Num.19 Test.31 Test.45;
|
||||
jump Test.41 Test.32 Test.43 Test.44;
|
||||
in
|
||||
let #Derived_gen.4 : Int1 = lowlevel RefCountIsUnique Test.29;
|
||||
if #Derived_gen.4 then
|
||||
jump #Derived_gen.3 Test.29;
|
||||
let Bool.25 : Int1 = lowlevel RefCountIsUnique Test.29;
|
||||
if Bool.25 then
|
||||
jump Bool.24 Test.29;
|
||||
else
|
||||
inc Test.32;
|
||||
inc Test.33;
|
||||
decref Test.29;
|
||||
let #Derived_gen.8 : [<rnu><null>, C *self *self] = NullPointer;
|
||||
jump #Derived_gen.3 #Derived_gen.8;
|
||||
let Bool.29 : [<rnu><null>, C *self *self] = NullPointer;
|
||||
jump Bool.24 Bool.29;
|
||||
else
|
||||
let Test.48 : U8 = 1i64;
|
||||
let Test.49 : U8 = GetTagId Test.30;
|
||||
|
@ -39,8 +39,8 @@ procedure Test.5 (#Derived_gen.0, #Derived_gen.1, #Derived_gen.2):
|
|||
if Test.50 then
|
||||
let Test.35 : [<rnu><null>, C *self *self] = UnionAtIndex (Id 1) (Index 0) Test.30;
|
||||
let Test.36 : [<rnu>C [<rnu><null>, C *self *self] *self, <null>] = UnionAtIndex (Id 1) (Index 1) Test.30;
|
||||
let #Derived_gen.5 : Int1 = lowlevel RefCountIsUnique Test.30;
|
||||
if #Derived_gen.5 then
|
||||
let Bool.26 : Int1 = lowlevel RefCountIsUnique Test.30;
|
||||
if Bool.26 then
|
||||
free Test.30;
|
||||
jump Test.41 Test.35 Test.36 Test.31;
|
||||
else
|
||||
|
@ -51,7 +51,7 @@ procedure Test.5 (#Derived_gen.0, #Derived_gen.1, #Derived_gen.2):
|
|||
else
|
||||
ret Test.31;
|
||||
in
|
||||
jump Test.41 #Derived_gen.0 #Derived_gen.1 #Derived_gen.2;
|
||||
jump Test.41 Bool.21 Bool.22 Bool.23;
|
||||
|
||||
procedure Test.0 ():
|
||||
let Test.64 : [<rnu><null>, C *self *self] = TagId(1) ;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
procedure List.101 (#Derived_gen.0, #Derived_gen.1, #Derived_gen.2, #Derived_gen.3, #Derived_gen.4):
|
||||
procedure List.101 (Bool.21, Bool.22, Bool.23, Bool.24, Bool.25):
|
||||
joinpoint List.681 List.175 List.176 List.177 List.178 List.179:
|
||||
let List.683 : Int1 = CallByName Num.22 List.178 List.179;
|
||||
if List.683 then
|
||||
|
@ -11,8 +11,8 @@ procedure List.101 (#Derived_gen.0, #Derived_gen.1, #Derived_gen.2, #Derived_gen
|
|||
dec List.175;
|
||||
ret List.176;
|
||||
in
|
||||
inc #Derived_gen.0;
|
||||
jump List.681 #Derived_gen.0 #Derived_gen.1 #Derived_gen.2 #Derived_gen.3 #Derived_gen.4;
|
||||
inc Bool.21;
|
||||
jump List.681 Bool.21 Bool.22 Bool.23 Bool.24 Bool.25;
|
||||
|
||||
procedure List.18 (List.172, List.173, List.174):
|
||||
let List.679 : U64 = 0i64;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
procedure List.101 (#Derived_gen.0, #Derived_gen.1, #Derived_gen.2, #Derived_gen.3, #Derived_gen.4):
|
||||
procedure List.101 (Bool.21, Bool.22, Bool.23, Bool.24, Bool.25):
|
||||
joinpoint List.681 List.175 List.176 List.177 List.178 List.179:
|
||||
let List.683 : Int1 = CallByName Num.22 List.178 List.179;
|
||||
if List.683 then
|
||||
|
@ -11,8 +11,8 @@ procedure List.101 (#Derived_gen.0, #Derived_gen.1, #Derived_gen.2, #Derived_gen
|
|||
dec List.175;
|
||||
ret List.176;
|
||||
in
|
||||
inc #Derived_gen.0;
|
||||
jump List.681 #Derived_gen.0 #Derived_gen.1 #Derived_gen.2 #Derived_gen.3 #Derived_gen.4;
|
||||
inc Bool.21;
|
||||
jump List.681 Bool.21 Bool.22 Bool.23 Bool.24 Bool.25;
|
||||
|
||||
procedure List.18 (List.172, List.173, List.174):
|
||||
let List.679 : U64 = 0i64;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
procedure List.101 (#Derived_gen.8, #Derived_gen.9, #Derived_gen.10, #Derived_gen.11, #Derived_gen.12):
|
||||
procedure List.101 (Bool.34, Bool.35, Bool.36, Bool.37, Bool.38):
|
||||
joinpoint List.678 List.175 List.176 List.177 List.178 List.179:
|
||||
let List.680 : Int1 = CallByName Num.22 List.178 List.179;
|
||||
if List.680 then
|
||||
|
@ -11,8 +11,8 @@ procedure List.101 (#Derived_gen.8, #Derived_gen.9, #Derived_gen.10, #Derived_ge
|
|||
dec List.175;
|
||||
ret List.176;
|
||||
in
|
||||
inc #Derived_gen.8;
|
||||
jump List.678 #Derived_gen.8 #Derived_gen.9 #Derived_gen.10 #Derived_gen.11 #Derived_gen.12;
|
||||
inc Bool.34;
|
||||
jump List.678 Bool.34 Bool.35 Bool.36 Bool.37 Bool.38;
|
||||
|
||||
procedure List.18 (List.172, List.173, List.174):
|
||||
let List.676 : U64 = 0i64;
|
||||
|
@ -38,8 +38,8 @@ procedure Num.51 (#Attr.2, #Attr.3):
|
|||
|
||||
procedure Test.10 (Test.69, #Attr.12):
|
||||
let Test.72 : {} = UnionAtIndex (Id 0) (Index 0) #Attr.12;
|
||||
let #Derived_gen.18 : Int1 = lowlevel RefCountIsUnique #Attr.12;
|
||||
if #Derived_gen.18 then
|
||||
let Bool.39 : Int1 = lowlevel RefCountIsUnique #Attr.12;
|
||||
if Bool.39 then
|
||||
free #Attr.12;
|
||||
ret Test.72;
|
||||
else
|
||||
|
@ -53,7 +53,7 @@ procedure Test.10 (Test.69, #Attr.12):
|
|||
procedure Test.14 (Test.45, #Attr.12):
|
||||
let Test.55 : {{}, []} = UnionAtIndex (Id 1) (Index 1) #Attr.12;
|
||||
let Test.54 : [<r>C {}, C *self {{}, []}] = UnionAtIndex (Id 1) (Index 0) #Attr.12;
|
||||
joinpoint #Derived_gen.19:
|
||||
joinpoint Bool.40:
|
||||
let Test.50 : {} = Struct {};
|
||||
let Test.51 : U8 = GetTagId Test.54;
|
||||
joinpoint Test.52 Test.15:
|
||||
|
@ -80,14 +80,14 @@ procedure Test.14 (Test.45, #Attr.12):
|
|||
jump Test.52 Test.53;
|
||||
|
||||
in
|
||||
let #Derived_gen.20 : Int1 = lowlevel RefCountIsUnique #Attr.12;
|
||||
if #Derived_gen.20 then
|
||||
let Bool.41 : Int1 = lowlevel RefCountIsUnique #Attr.12;
|
||||
if Bool.41 then
|
||||
free #Attr.12;
|
||||
jump #Derived_gen.19;
|
||||
jump Bool.40;
|
||||
else
|
||||
inc Test.54;
|
||||
decref #Attr.12;
|
||||
jump #Derived_gen.19;
|
||||
jump Bool.40;
|
||||
|
||||
procedure Test.20 (Test.21, Test.18):
|
||||
let Test.23 : [C {}, C []] = CallByName Test.32 Test.21 Test.18;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
procedure Bool.1 ():
|
||||
let Bool.23 : Int1 = false;
|
||||
ret Bool.23;
|
||||
let Bool.21 : Int1 = false;
|
||||
ret Bool.21;
|
||||
|
||||
procedure Test.2 (Test.6):
|
||||
let Test.22 : U8 = 1i64;
|
||||
|
@ -8,7 +8,7 @@ procedure Test.2 (Test.6):
|
|||
let Test.24 : Int1 = lowlevel Eq Test.22 Test.23;
|
||||
if Test.24 then
|
||||
let Test.7 : [<r>C List *self, C *self] = UnionAtIndex (Id 1) (Index 0) Test.6;
|
||||
joinpoint #Derived_gen.1:
|
||||
joinpoint Bool.23:
|
||||
let Test.8 : Str = CallByName Test.2 Test.7;
|
||||
let Test.18 : Int1 = CallByName Bool.1;
|
||||
if Test.18 then
|
||||
|
@ -18,29 +18,29 @@ procedure Test.2 (Test.6):
|
|||
let Test.17 : Str = "foo";
|
||||
ret Test.17;
|
||||
in
|
||||
let #Derived_gen.2 : Int1 = lowlevel RefCountIsUnique Test.6;
|
||||
if #Derived_gen.2 then
|
||||
let Bool.24 : Int1 = lowlevel RefCountIsUnique Test.6;
|
||||
if Bool.24 then
|
||||
free Test.6;
|
||||
jump #Derived_gen.1;
|
||||
jump Bool.23;
|
||||
else
|
||||
inc Test.7;
|
||||
decref Test.6;
|
||||
jump #Derived_gen.1;
|
||||
jump Bool.23;
|
||||
else
|
||||
let Test.9 : List [<r>C List [<r>C List *self, C *self], C [<r>C List *self, C *self]] = UnionAtIndex (Id 0) (Index 0) Test.6;
|
||||
joinpoint #Derived_gen.3:
|
||||
joinpoint Bool.25:
|
||||
dec Test.9;
|
||||
let Test.21 : Str = "ValueNotExposed { module_name: ModuleName(IdentStr { string: \"Result\" }), ident: Ident(IdentStr { string: \"withDefault\" }), region: @662-680, exposed_values: ['is_err', 'on_err', 'map_ok', 'map_err', 'with_default', 'try', 'is_ok', 'map_both', 'map2', 'on_err!'] }";
|
||||
Crash Test.21
|
||||
in
|
||||
let #Derived_gen.4 : Int1 = lowlevel RefCountIsUnique Test.6;
|
||||
if #Derived_gen.4 then
|
||||
let Bool.26 : Int1 = lowlevel RefCountIsUnique Test.6;
|
||||
if Bool.26 then
|
||||
free Test.6;
|
||||
jump #Derived_gen.3;
|
||||
jump Bool.25;
|
||||
else
|
||||
inc Test.9;
|
||||
decref Test.6;
|
||||
jump #Derived_gen.3;
|
||||
jump Bool.25;
|
||||
|
||||
procedure Test.0 ():
|
||||
let Test.25 : List [<r>C List [<r>C List *self, C *self], C [<r>C List *self, C *self]] = Array [];
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
procedure Bool.2 ():
|
||||
let Bool.23 : Int1 = true;
|
||||
ret Bool.23;
|
||||
let Bool.21 : Int1 = true;
|
||||
ret Bool.21;
|
||||
|
||||
procedure List.101 (#Derived_gen.5, #Derived_gen.6, #Derived_gen.7, #Derived_gen.8, #Derived_gen.9):
|
||||
procedure List.101 (Bool.29, Bool.30, Bool.31, Bool.32, Bool.33):
|
||||
joinpoint List.678 List.175 List.176 List.177 List.178 List.179:
|
||||
let List.680 : Int1 = CallByName Num.22 List.178 List.179;
|
||||
if List.680 then
|
||||
|
@ -15,8 +15,8 @@ procedure List.101 (#Derived_gen.5, #Derived_gen.6, #Derived_gen.7, #Derived_gen
|
|||
dec List.175;
|
||||
ret List.176;
|
||||
in
|
||||
inc #Derived_gen.5;
|
||||
jump List.678 #Derived_gen.5 #Derived_gen.6 #Derived_gen.7 #Derived_gen.8 #Derived_gen.9;
|
||||
inc Bool.29;
|
||||
jump List.678 Bool.29 Bool.30 Bool.31 Bool.32 Bool.33;
|
||||
|
||||
procedure List.18 (List.172, List.173, List.174):
|
||||
let List.676 : U64 = 0i64;
|
||||
|
@ -41,17 +41,17 @@ procedure Num.51 (#Attr.2, #Attr.3):
|
|||
ret Num.283;
|
||||
|
||||
procedure Str.3 (#Attr.2, #Attr.3):
|
||||
let Str.248 : Str = lowlevel StrConcat #Attr.2 #Attr.3;
|
||||
ret Str.248;
|
||||
let Str.387 : Str = lowlevel StrConcat #Attr.2 #Attr.3;
|
||||
ret Str.387;
|
||||
|
||||
procedure Test.1 (Test.5):
|
||||
ret Test.5;
|
||||
|
||||
procedure Test.11 (#Derived_gen.10, #Derived_gen.11):
|
||||
procedure Test.11 (Bool.27, Bool.28):
|
||||
joinpoint Test.27 Test.12 #Attr.12:
|
||||
let Test.34 : Int1 = UnionAtIndex (Id 2) (Index 1) #Attr.12;
|
||||
let Test.33 : [<rnw><null>, C *self Int1, C *self Int1] = UnionAtIndex (Id 2) (Index 0) #Attr.12;
|
||||
joinpoint #Derived_gen.14:
|
||||
joinpoint Bool.36:
|
||||
joinpoint Test.31 Test.29:
|
||||
let Test.30 : U8 = GetTagId Test.33;
|
||||
switch Test.30:
|
||||
|
@ -78,16 +78,16 @@ procedure Test.11 (#Derived_gen.10, #Derived_gen.11):
|
|||
jump Test.31 Test.32;
|
||||
|
||||
in
|
||||
let #Derived_gen.15 : Int1 = lowlevel RefCountIsUnique #Attr.12;
|
||||
if #Derived_gen.15 then
|
||||
let Bool.37 : Int1 = lowlevel RefCountIsUnique #Attr.12;
|
||||
if Bool.37 then
|
||||
free #Attr.12;
|
||||
jump #Derived_gen.14;
|
||||
jump Bool.36;
|
||||
else
|
||||
inc Test.33;
|
||||
decref #Attr.12;
|
||||
jump #Derived_gen.14;
|
||||
jump Bool.36;
|
||||
in
|
||||
jump Test.27 #Derived_gen.10 #Derived_gen.11;
|
||||
jump Test.27 Bool.27 Bool.28;
|
||||
|
||||
procedure Test.2 (Test.13):
|
||||
ret Test.13;
|
||||
|
@ -118,7 +118,7 @@ procedure Test.6 (Test.7, Test.8, Test.5):
|
|||
procedure Test.9 (Test.10, #Attr.12):
|
||||
let Test.43 : Int1 = UnionAtIndex (Id 1) (Index 1) #Attr.12;
|
||||
let Test.42 : [<rnw><null>, C *self Int1, C *self Int1] = UnionAtIndex (Id 1) (Index 0) #Attr.12;
|
||||
joinpoint #Derived_gen.12:
|
||||
joinpoint Bool.34:
|
||||
let Test.39 : U8 = GetTagId Test.42;
|
||||
joinpoint Test.40 Test.38:
|
||||
switch Test.43:
|
||||
|
@ -146,14 +146,14 @@ procedure Test.9 (Test.10, #Attr.12):
|
|||
jump Test.40 Test.41;
|
||||
|
||||
in
|
||||
let #Derived_gen.13 : Int1 = lowlevel RefCountIsUnique #Attr.12;
|
||||
if #Derived_gen.13 then
|
||||
let Bool.35 : Int1 = lowlevel RefCountIsUnique #Attr.12;
|
||||
if Bool.35 then
|
||||
free #Attr.12;
|
||||
jump #Derived_gen.12;
|
||||
jump Bool.34;
|
||||
else
|
||||
inc Test.42;
|
||||
decref #Attr.12;
|
||||
jump #Derived_gen.12;
|
||||
jump Bool.34;
|
||||
|
||||
procedure Test.0 ():
|
||||
let Test.45 : Int1 = false;
|
||||
|
|
18
crates/compiler/test_mono/generated/dbg_expr.txt
generated
18
crates/compiler/test_mono/generated/dbg_expr.txt
generated
|
@ -43,14 +43,14 @@ procedure Num.96 (#Attr.2):
|
|||
ret Num.284;
|
||||
|
||||
procedure Str.3 (#Attr.2, #Attr.3):
|
||||
let Str.246 : Str = lowlevel StrConcat #Attr.2 #Attr.3;
|
||||
ret Str.246;
|
||||
let Str.385 : Str = lowlevel StrConcat #Attr.2 #Attr.3;
|
||||
ret Str.385;
|
||||
|
||||
procedure Test.0 ():
|
||||
let Test.5 : I64 = 1i64;
|
||||
let Test.2 : I64 = 2i64;
|
||||
let Test.3 : Str = CallByName Inspect.33 Test.2;
|
||||
dbg Test.3;
|
||||
dec Test.3;
|
||||
let Test.4 : I64 = CallByName Num.19 Test.5 Test.2;
|
||||
ret Test.4;
|
||||
let Test.4 : I64 = 1i64;
|
||||
let Test.1 : I64 = 2i64;
|
||||
let Test.2 : Str = CallByName Inspect.33 Test.1;
|
||||
dbg Test.2;
|
||||
dec Test.2;
|
||||
let Test.3 : I64 = CallByName Num.19 Test.4 Test.1;
|
||||
ret Test.3;
|
||||
|
|
331
crates/compiler/test_mono/generated/dbg_in_expect.txt
generated
331
crates/compiler/test_mono/generated/dbg_in_expect.txt
generated
|
@ -1,17 +1,17 @@
|
|||
procedure Bool.11 (#Attr.2, #Attr.3):
|
||||
let Bool.25 : Int1 = lowlevel Eq #Attr.2 #Attr.3;
|
||||
ret Bool.25;
|
||||
|
||||
procedure Bool.11 (#Attr.2, #Attr.3):
|
||||
let Bool.26 : Int1 = lowlevel Eq #Attr.2 #Attr.3;
|
||||
ret Bool.26;
|
||||
procedure Bool.1 ():
|
||||
let Bool.22 : Int1 = false;
|
||||
ret Bool.22;
|
||||
|
||||
procedure Bool.2 ():
|
||||
let Bool.23 : Int1 = true;
|
||||
let Bool.21 : Int1 = true;
|
||||
ret Bool.21;
|
||||
|
||||
procedure Bool.9 (#Attr.2, #Attr.3):
|
||||
let Bool.23 : Int1 = lowlevel Eq #Attr.2 #Attr.3;
|
||||
ret Bool.23;
|
||||
|
||||
procedure Bool.3 (#Attr.2, #Attr.3):
|
||||
let Bool.24 : Int1 = lowlevel And #Attr.2 #Attr.3;
|
||||
procedure Bool.9 (#Attr.2, #Attr.3):
|
||||
let Bool.24 : Int1 = lowlevel Eq #Attr.2 #Attr.3;
|
||||
ret Bool.24;
|
||||
|
||||
procedure Inspect.245 (Inspect.246, Inspect.244):
|
||||
|
@ -104,181 +104,184 @@ procedure Num.77 (#Attr.2, #Attr.3):
|
|||
ret Num.293;
|
||||
|
||||
procedure Str.20 (#Attr.2):
|
||||
let Str.313 : Str = lowlevel StrWithCapacity #Attr.2;
|
||||
ret Str.313;
|
||||
let Str.453 : Str = lowlevel StrWithCapacity #Attr.2;
|
||||
ret Str.453;
|
||||
|
||||
procedure Str.3 (#Attr.2, #Attr.3):
|
||||
let Str.246 : Str = lowlevel StrConcat #Attr.2 #Attr.3;
|
||||
ret Str.246;
|
||||
let Str.385 : Str = lowlevel StrConcat #Attr.2 #Attr.3;
|
||||
ret Str.385;
|
||||
|
||||
procedure Str.35 (#Attr.2, #Attr.3):
|
||||
let Str.303 : U8 = lowlevel StrGetUnsafe #Attr.2 #Attr.3;
|
||||
ret Str.303;
|
||||
let Str.443 : U8 = lowlevel StrGetUnsafe #Attr.2 #Attr.3;
|
||||
ret Str.443;
|
||||
|
||||
procedure Str.36 (#Attr.2):
|
||||
let Str.266 : U64 = lowlevel StrCountUtf8Bytes #Attr.2;
|
||||
ret Str.266;
|
||||
let Str.405 : U64 = lowlevel StrCountUtf8Bytes #Attr.2;
|
||||
ret Str.405;
|
||||
|
||||
procedure Str.37 (#Attr.2, #Attr.3, #Attr.4):
|
||||
let Str.264 : Str = lowlevel StrSubstringUnsafe #Attr.2 #Attr.3 #Attr.4;
|
||||
ret Str.264;
|
||||
let Str.403 : Str = lowlevel StrSubstringUnsafe #Attr.2 #Attr.3 #Attr.4;
|
||||
ret Str.403;
|
||||
|
||||
procedure Str.38 (Str.112, Str.113):
|
||||
let Str.260 : [C , C U64] = CallByName Str.57 Str.112 Str.113;
|
||||
let Str.273 : U8 = 1i64;
|
||||
let Str.274 : U8 = GetTagId Str.260;
|
||||
let Str.275 : Int1 = lowlevel Eq Str.273 Str.274;
|
||||
if Str.275 then
|
||||
let Str.114 : U64 = UnionAtIndex (Id 1) (Index 0) Str.260;
|
||||
let Str.269 : U64 = CallByName Str.36 Str.112;
|
||||
let Str.270 : U64 = CallByName Str.36 Str.113;
|
||||
let Str.268 : U64 = CallByName Num.20 Str.269 Str.270;
|
||||
let Str.115 : U64 = CallByName Num.20 Str.268 Str.114;
|
||||
let Str.267 : U64 = 0i64;
|
||||
inc Str.112;
|
||||
let Str.116 : Str = CallByName Str.37 Str.112 Str.267 Str.114;
|
||||
let Str.265 : U64 = CallByName Str.36 Str.113;
|
||||
let Str.263 : U64 = CallByName Num.51 Str.114 Str.265;
|
||||
let Str.117 : Str = CallByName Str.37 Str.112 Str.263 Str.115;
|
||||
let Str.262 : {Str, Str} = Struct {Str.117, Str.116};
|
||||
let Str.261 : [C {}, C {Str, Str}] = TagId(1) Str.262;
|
||||
ret Str.261;
|
||||
procedure Str.38 (Str.213, Str.214):
|
||||
let Str.399 : [C , C U64] = CallByName Str.65 Str.213 Str.214;
|
||||
let Str.412 : U8 = 1i64;
|
||||
let Str.413 : U8 = GetTagId Str.399;
|
||||
let Str.414 : Int1 = lowlevel Eq Str.412 Str.413;
|
||||
if Str.414 then
|
||||
let Str.215 : U64 = UnionAtIndex (Id 1) (Index 0) Str.399;
|
||||
let Str.408 : U64 = CallByName Str.36 Str.213;
|
||||
let Str.409 : U64 = CallByName Str.36 Str.214;
|
||||
let Str.407 : U64 = CallByName Num.20 Str.408 Str.409;
|
||||
let Str.216 : U64 = CallByName Num.20 Str.407 Str.215;
|
||||
let Str.406 : U64 = 0i64;
|
||||
inc Str.213;
|
||||
let Str.217 : Str = CallByName Str.37 Str.213 Str.406 Str.215;
|
||||
let Str.404 : U64 = CallByName Str.36 Str.214;
|
||||
let Str.402 : U64 = CallByName Num.51 Str.215 Str.404;
|
||||
let Str.218 : Str = CallByName Str.37 Str.213 Str.402 Str.216;
|
||||
let Str.401 : {Str, Str} = Struct {Str.218, Str.217};
|
||||
let Str.400 : [C {}, C {Str, Str}] = TagId(1) Str.401;
|
||||
ret Str.400;
|
||||
else
|
||||
dec Str.112;
|
||||
let Str.272 : {} = Struct {};
|
||||
let Str.271 : [C {}, C {Str, Str}] = TagId(0) Str.272;
|
||||
ret Str.271;
|
||||
dec Str.213;
|
||||
let Str.411 : {} = Struct {};
|
||||
let Str.410 : [C {}, C {Str, Str}] = TagId(0) Str.411;
|
||||
ret Str.410;
|
||||
|
||||
procedure Str.45 (Str.91, Str.92, Str.93):
|
||||
inc Str.91;
|
||||
let Str.341 : [C {}, C {Str, Str}] = CallByName Str.38 Str.91 Str.92;
|
||||
let Str.349 : U8 = 1i64;
|
||||
let Str.350 : U8 = GetTagId Str.341;
|
||||
let Str.351 : Int1 = lowlevel Eq Str.349 Str.350;
|
||||
if Str.351 then
|
||||
let Str.348 : {Str, Str} = UnionAtIndex (Id 1) (Index 0) Str.341;
|
||||
let Str.95 : Str = StructAtIndex 0 Str.348;
|
||||
let Str.94 : Str = StructAtIndex 1 Str.348;
|
||||
let Str.346 : U64 = CallByName Str.36 Str.91;
|
||||
dec Str.91;
|
||||
let Str.345 : Str = CallByName Str.20 Str.346;
|
||||
let Str.344 : Str = CallByName Str.3 Str.345 Str.94;
|
||||
dec Str.94;
|
||||
let Str.343 : Str = CallByName Str.3 Str.344 Str.93;
|
||||
let Str.342 : Str = CallByName Str.56 Str.343 Str.95 Str.92 Str.93;
|
||||
ret Str.342;
|
||||
procedure Str.45 (Str.192, Str.193, Str.194):
|
||||
inc Str.192;
|
||||
let Str.481 : [C {}, C {Str, Str}] = CallByName Str.38 Str.192 Str.193;
|
||||
let Str.489 : U8 = 1i64;
|
||||
let Str.490 : U8 = GetTagId Str.481;
|
||||
let Str.491 : Int1 = lowlevel Eq Str.489 Str.490;
|
||||
if Str.491 then
|
||||
let Str.488 : {Str, Str} = UnionAtIndex (Id 1) (Index 0) Str.481;
|
||||
let Str.196 : Str = StructAtIndex 0 Str.488;
|
||||
let Str.195 : Str = StructAtIndex 1 Str.488;
|
||||
let Str.486 : U64 = CallByName Str.36 Str.192;
|
||||
dec Str.192;
|
||||
let Str.485 : Str = CallByName Str.20 Str.486;
|
||||
let Str.484 : Str = CallByName Str.3 Str.485 Str.195;
|
||||
dec Str.195;
|
||||
let Str.483 : Str = CallByName Str.3 Str.484 Str.194;
|
||||
let Str.482 : Str = CallByName Str.64 Str.483 Str.196 Str.193 Str.194;
|
||||
ret Str.482;
|
||||
else
|
||||
dec Str.341;
|
||||
ret Str.91;
|
||||
dec Str.481;
|
||||
ret Str.192;
|
||||
|
||||
procedure Str.56 (#Derived_gen.5, #Derived_gen.6, #Derived_gen.7, #Derived_gen.8):
|
||||
joinpoint Str.250 Str.96 Str.97 Str.98 Str.99:
|
||||
inc Str.97;
|
||||
let Str.251 : [C {}, C {Str, Str}] = CallByName Str.38 Str.97 Str.98;
|
||||
let Str.257 : U8 = 1i64;
|
||||
let Str.258 : U8 = GetTagId Str.251;
|
||||
let Str.259 : Int1 = lowlevel Eq Str.257 Str.258;
|
||||
if Str.259 then
|
||||
dec Str.97;
|
||||
let Str.256 : {Str, Str} = UnionAtIndex (Id 1) (Index 0) Str.251;
|
||||
let Str.101 : Str = StructAtIndex 0 Str.256;
|
||||
let Str.100 : Str = StructAtIndex 1 Str.256;
|
||||
let Str.254 : Str = CallByName Str.3 Str.96 Str.100;
|
||||
dec Str.100;
|
||||
let Str.253 : Str = CallByName Str.3 Str.254 Str.99;
|
||||
jump Str.250 Str.253 Str.101 Str.98 Str.99;
|
||||
procedure Str.64 (#Derived_gen.0, #Derived_gen.1, #Derived_gen.2, #Derived_gen.3):
|
||||
joinpoint Str.389 Str.197 Str.198 Str.199 Str.200:
|
||||
inc Str.198;
|
||||
let Str.390 : [C {}, C {Str, Str}] = CallByName Str.38 Str.198 Str.199;
|
||||
let Str.396 : U8 = 1i64;
|
||||
let Str.397 : U8 = GetTagId Str.390;
|
||||
let Str.398 : Int1 = lowlevel Eq Str.396 Str.397;
|
||||
if Str.398 then
|
||||
dec Str.198;
|
||||
let Str.395 : {Str, Str} = UnionAtIndex (Id 1) (Index 0) Str.390;
|
||||
let Str.202 : Str = StructAtIndex 0 Str.395;
|
||||
let Str.201 : Str = StructAtIndex 1 Str.395;
|
||||
let Str.393 : Str = CallByName Str.3 Str.197 Str.201;
|
||||
dec Str.201;
|
||||
let Str.392 : Str = CallByName Str.3 Str.393 Str.200;
|
||||
jump Str.389 Str.392 Str.202 Str.199 Str.200;
|
||||
else
|
||||
dec Str.98;
|
||||
dec Str.251;
|
||||
dec Str.99;
|
||||
let Str.255 : Str = CallByName Str.3 Str.96 Str.97;
|
||||
dec Str.97;
|
||||
ret Str.255;
|
||||
dec Str.199;
|
||||
dec Str.390;
|
||||
dec Str.200;
|
||||
let Str.394 : Str = CallByName Str.3 Str.197 Str.198;
|
||||
dec Str.198;
|
||||
ret Str.394;
|
||||
in
|
||||
inc #Derived_gen.7;
|
||||
inc #Derived_gen.8;
|
||||
jump Str.250 #Derived_gen.5 #Derived_gen.6 #Derived_gen.7 #Derived_gen.8;
|
||||
|
||||
procedure Str.57 (Str.121, Str.122):
|
||||
let Str.123 : U64 = CallByName Str.36 Str.121;
|
||||
let Str.124 : U64 = CallByName Str.36 Str.122;
|
||||
let Str.125 : U64 = CallByName Num.77 Str.123 Str.124;
|
||||
let Str.277 : U64 = 0i64;
|
||||
let Str.276 : [C , C U64] = CallByName Str.58 Str.121 Str.122 Str.277 Str.125;
|
||||
ret Str.276;
|
||||
|
||||
procedure Str.58 (#Derived_gen.1, #Derived_gen.2, #Derived_gen.3, #Derived_gen.4):
|
||||
joinpoint Str.278 Str.126 Str.127 Str.128 Str.129:
|
||||
let Str.280 : Int1 = CallByName Num.23 Str.128 Str.129;
|
||||
if Str.280 then
|
||||
let Str.284 : Int1 = CallByName Str.62 Str.126 Str.128 Str.127;
|
||||
if Str.284 then
|
||||
dec Str.127;
|
||||
dec Str.126;
|
||||
let Str.285 : [C , C U64] = TagId(1) Str.128;
|
||||
ret Str.285;
|
||||
else
|
||||
let Str.283 : U64 = 1i64;
|
||||
let Str.282 : U64 = CallByName Num.51 Str.128 Str.283;
|
||||
jump Str.278 Str.126 Str.127 Str.282 Str.129;
|
||||
else
|
||||
dec Str.127;
|
||||
dec Str.126;
|
||||
let Str.279 : [C , C U64] = TagId(0) ;
|
||||
ret Str.279;
|
||||
in
|
||||
inc #Derived_gen.1;
|
||||
inc #Derived_gen.3;
|
||||
inc #Derived_gen.2;
|
||||
jump Str.278 #Derived_gen.1 #Derived_gen.2 #Derived_gen.3 #Derived_gen.4;
|
||||
jump Str.389 #Derived_gen.0 #Derived_gen.1 #Derived_gen.2 #Derived_gen.3;
|
||||
|
||||
procedure Str.61 (Str.152, Str.153):
|
||||
let Str.308 : Int1 = CallByName Num.22 Str.152 Str.153;
|
||||
if Str.308 then
|
||||
ret Str.152;
|
||||
procedure Str.65 (Str.222, Str.223):
|
||||
let Str.224 : U64 = CallByName Str.36 Str.222;
|
||||
let Str.225 : U64 = CallByName Str.36 Str.223;
|
||||
let Str.226 : U64 = CallByName Num.77 Str.224 Str.225;
|
||||
let Str.416 : U64 = 0i64;
|
||||
let Str.415 : [C , C U64] = CallByName Str.66 Str.222 Str.223 Str.416 Str.226;
|
||||
ret Str.415;
|
||||
|
||||
procedure Str.66 (#Derived_gen.4, #Derived_gen.5, #Derived_gen.6, #Derived_gen.7):
|
||||
joinpoint Str.417 Str.227 Str.228 Str.229 Str.230:
|
||||
let Str.419 : Int1 = CallByName Num.23 Str.229 Str.230;
|
||||
if Str.419 then
|
||||
let Str.423 : Int1 = CallByName Str.70 Str.227 Str.229 Str.228;
|
||||
if Str.423 then
|
||||
dec Str.227;
|
||||
dec Str.228;
|
||||
let Str.424 : [C , C U64] = TagId(1) Str.229;
|
||||
ret Str.424;
|
||||
else
|
||||
let Str.422 : U64 = 1i64;
|
||||
let Str.421 : U64 = CallByName Num.51 Str.229 Str.422;
|
||||
jump Str.417 Str.227 Str.228 Str.421 Str.230;
|
||||
else
|
||||
dec Str.227;
|
||||
dec Str.228;
|
||||
let Str.418 : [C , C U64] = TagId(0) ;
|
||||
ret Str.418;
|
||||
in
|
||||
inc #Derived_gen.5;
|
||||
inc #Derived_gen.4;
|
||||
jump Str.417 #Derived_gen.4 #Derived_gen.5 #Derived_gen.6 #Derived_gen.7;
|
||||
|
||||
procedure Str.69 (Str.253, Str.254):
|
||||
let Str.448 : Int1 = CallByName Num.22 Str.253 Str.254;
|
||||
if Str.448 then
|
||||
ret Str.253;
|
||||
else
|
||||
ret Str.153;
|
||||
ret Str.254;
|
||||
|
||||
procedure Str.62 (Str.154, Str.155, Str.156):
|
||||
let Str.157 : U64 = CallByName Str.36 Str.154;
|
||||
let Str.158 : U64 = CallByName Str.36 Str.156;
|
||||
let Str.306 : U64 = CallByName Num.53 Str.155 Str.158;
|
||||
let Str.159 : U64 = CallByName Str.61 Str.306 Str.157;
|
||||
let Str.305 : U64 = 0i64;
|
||||
inc Str.156;
|
||||
inc Str.154;
|
||||
let Str.287 : {U64, Str, U64, Str, U64, U64} = Struct {Str.159, Str.154, Str.155, Str.156, Str.305, Str.158};
|
||||
let Str.286 : Int1 = CallByName Str.63 Str.287;
|
||||
ret Str.286;
|
||||
procedure Str.70 (Str.255, Str.256, Str.257):
|
||||
let Str.258 : U64 = CallByName Str.36 Str.255;
|
||||
let Str.259 : U64 = CallByName Str.36 Str.257;
|
||||
let Str.446 : U64 = CallByName Num.53 Str.256 Str.259;
|
||||
let Str.260 : U64 = CallByName Str.69 Str.446 Str.258;
|
||||
let Str.445 : U64 = 0i64;
|
||||
inc Str.255;
|
||||
inc Str.257;
|
||||
let Str.426 : {U64, Str, U64, Str, U64, U64} = Struct {Str.260, Str.255, Str.256, Str.257, Str.445, Str.259};
|
||||
let Str.425 : Int1 = CallByName Str.71 Str.426;
|
||||
ret Str.425;
|
||||
|
||||
procedure Str.63 (Str.160):
|
||||
let Str.166 : U64 = StructAtIndex 0 Str.160;
|
||||
let Str.161 : Str = StructAtIndex 1 Str.160;
|
||||
let Str.162 : U64 = StructAtIndex 2 Str.160;
|
||||
let Str.163 : Str = StructAtIndex 3 Str.160;
|
||||
let Str.164 : U64 = StructAtIndex 4 Str.160;
|
||||
let Str.165 : U64 = StructAtIndex 5 Str.160;
|
||||
let Str.167 : Int1 = CallByName Num.25 Str.162 Str.166;
|
||||
if Str.167 then
|
||||
dec Str.163;
|
||||
dec Str.161;
|
||||
let Str.168 : Int1 = CallByName Bool.11 Str.164 Str.165;
|
||||
ret Str.168;
|
||||
procedure Str.71 (Str.261):
|
||||
let Str.267 : U64 = StructAtIndex 0 Str.261;
|
||||
let Str.262 : Str = StructAtIndex 1 Str.261;
|
||||
let Str.263 : U64 = StructAtIndex 2 Str.261;
|
||||
let Str.264 : Str = StructAtIndex 3 Str.261;
|
||||
let Str.265 : U64 = StructAtIndex 4 Str.261;
|
||||
let Str.266 : U64 = StructAtIndex 5 Str.261;
|
||||
let Str.268 : Int1 = CallByName Num.25 Str.263 Str.267;
|
||||
if Str.268 then
|
||||
dec Str.262;
|
||||
dec Str.264;
|
||||
let Str.269 : Int1 = CallByName Bool.9 Str.265 Str.266;
|
||||
ret Str.269;
|
||||
else
|
||||
let Str.301 : U8 = CallByName Str.35 Str.161 Str.162;
|
||||
let Str.302 : U8 = CallByName Str.35 Str.163 Str.164;
|
||||
let Str.169 : Int1 = CallByName Bool.11 Str.301 Str.302;
|
||||
let Str.291 : U64 = StructAtIndex 0 Str.160;
|
||||
let Str.292 : Str = StructAtIndex 1 Str.160;
|
||||
let Str.294 : Str = StructAtIndex 3 Str.160;
|
||||
let Str.296 : U64 = StructAtIndex 5 Str.160;
|
||||
let Str.300 : U64 = 1i64;
|
||||
let Str.298 : U64 = CallByName Num.51 Str.164 Str.300;
|
||||
let Str.299 : U64 = 1i64;
|
||||
let Str.297 : U64 = CallByName Num.51 Str.162 Str.299;
|
||||
let Str.290 : {U64, Str, U64, Str, U64, U64} = Struct {Str.291, Str.292, Str.297, Str.294, Str.298, Str.296};
|
||||
let Str.170 : Int1 = CallByName Str.63 Str.290;
|
||||
let Str.289 : Int1 = CallByName Bool.3 Str.169 Str.170;
|
||||
ret Str.289;
|
||||
let Str.441 : U8 = CallByName Str.35 Str.262 Str.263;
|
||||
let Str.442 : U8 = CallByName Str.35 Str.264 Str.265;
|
||||
let Str.270 : Int1 = CallByName Bool.9 Str.441 Str.442;
|
||||
let Str.431 : U64 = StructAtIndex 0 Str.261;
|
||||
let Str.432 : Str = StructAtIndex 1 Str.261;
|
||||
let Str.434 : Str = StructAtIndex 3 Str.261;
|
||||
let Str.436 : U64 = StructAtIndex 5 Str.261;
|
||||
let Str.440 : U64 = 1i64;
|
||||
let Str.438 : U64 = CallByName Num.51 Str.265 Str.440;
|
||||
let Str.439 : U64 = 1i64;
|
||||
let Str.437 : U64 = CallByName Num.51 Str.263 Str.439;
|
||||
let Str.430 : {U64, Str, U64, Str, U64, U64} = Struct {Str.431, Str.432, Str.437, Str.434, Str.438, Str.436};
|
||||
let Str.271 : Int1 = CallByName Str.71 Str.430;
|
||||
if Str.270 then
|
||||
ret Str.271;
|
||||
else
|
||||
let Str.428 : Int1 = CallByName Bool.1;
|
||||
ret Str.428;
|
||||
|
||||
procedure Test.1 ():
|
||||
let Test.4 : Str = "";
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
procedure Bool.11 (#Attr.2, #Attr.3):
|
||||
let Bool.24 : Int1 = lowlevel Eq #Attr.2 #Attr.3;
|
||||
ret Bool.24;
|
||||
procedure Bool.1 ():
|
||||
let Bool.21 : Int1 = false;
|
||||
ret Bool.21;
|
||||
|
||||
procedure Bool.11 (#Attr.2, #Attr.3):
|
||||
let Bool.25 : Int1 = lowlevel Eq #Attr.2 #Attr.3;
|
||||
ret Bool.25;
|
||||
procedure Bool.9 (#Attr.2, #Attr.3):
|
||||
let Bool.22 : Int1 = lowlevel Eq #Attr.2 #Attr.3;
|
||||
ret Bool.22;
|
||||
|
||||
procedure Bool.3 (#Attr.2, #Attr.3):
|
||||
let Bool.23 : Int1 = lowlevel And #Attr.2 #Attr.3;
|
||||
procedure Bool.9 (#Attr.2, #Attr.3):
|
||||
let Bool.23 : Int1 = lowlevel Eq #Attr.2 #Attr.3;
|
||||
ret Bool.23;
|
||||
|
||||
procedure Inspect.245 (Inspect.246, Inspect.244):
|
||||
|
@ -100,192 +100,195 @@ procedure Num.77 (#Attr.2, #Attr.3):
|
|||
ret Num.293;
|
||||
|
||||
procedure Str.20 (#Attr.2):
|
||||
let Str.315 : Str = lowlevel StrWithCapacity #Attr.2;
|
||||
ret Str.315;
|
||||
let Str.455 : Str = lowlevel StrWithCapacity #Attr.2;
|
||||
ret Str.455;
|
||||
|
||||
procedure Str.3 (#Attr.2, #Attr.3):
|
||||
let Str.248 : Str = lowlevel StrConcat #Attr.2 #Attr.3;
|
||||
ret Str.248;
|
||||
let Str.387 : Str = lowlevel StrConcat #Attr.2 #Attr.3;
|
||||
ret Str.387;
|
||||
|
||||
procedure Str.35 (#Attr.2, #Attr.3):
|
||||
let Str.305 : U8 = lowlevel StrGetUnsafe #Attr.2 #Attr.3;
|
||||
ret Str.305;
|
||||
let Str.445 : U8 = lowlevel StrGetUnsafe #Attr.2 #Attr.3;
|
||||
ret Str.445;
|
||||
|
||||
procedure Str.36 (#Attr.2):
|
||||
let Str.268 : U64 = lowlevel StrCountUtf8Bytes #Attr.2;
|
||||
ret Str.268;
|
||||
let Str.407 : U64 = lowlevel StrCountUtf8Bytes #Attr.2;
|
||||
ret Str.407;
|
||||
|
||||
procedure Str.37 (#Attr.2, #Attr.3, #Attr.4):
|
||||
let Str.266 : Str = lowlevel StrSubstringUnsafe #Attr.2 #Attr.3 #Attr.4;
|
||||
ret Str.266;
|
||||
let Str.405 : Str = lowlevel StrSubstringUnsafe #Attr.2 #Attr.3 #Attr.4;
|
||||
ret Str.405;
|
||||
|
||||
procedure Str.38 (Str.112, Str.113):
|
||||
let Str.262 : [C , C U64] = CallByName Str.57 Str.112 Str.113;
|
||||
let Str.275 : U8 = 1i64;
|
||||
let Str.276 : U8 = GetTagId Str.262;
|
||||
let Str.277 : Int1 = lowlevel Eq Str.275 Str.276;
|
||||
if Str.277 then
|
||||
let Str.114 : U64 = UnionAtIndex (Id 1) (Index 0) Str.262;
|
||||
let Str.271 : U64 = CallByName Str.36 Str.112;
|
||||
let Str.272 : U64 = CallByName Str.36 Str.113;
|
||||
let Str.270 : U64 = CallByName Num.20 Str.271 Str.272;
|
||||
let Str.115 : U64 = CallByName Num.20 Str.270 Str.114;
|
||||
let Str.269 : U64 = 0i64;
|
||||
inc Str.112;
|
||||
let Str.116 : Str = CallByName Str.37 Str.112 Str.269 Str.114;
|
||||
let Str.267 : U64 = CallByName Str.36 Str.113;
|
||||
let Str.265 : U64 = CallByName Num.51 Str.114 Str.267;
|
||||
let Str.117 : Str = CallByName Str.37 Str.112 Str.265 Str.115;
|
||||
let Str.264 : {Str, Str} = Struct {Str.117, Str.116};
|
||||
let Str.263 : [C {}, C {Str, Str}] = TagId(1) Str.264;
|
||||
ret Str.263;
|
||||
procedure Str.38 (Str.213, Str.214):
|
||||
let Str.401 : [C , C U64] = CallByName Str.65 Str.213 Str.214;
|
||||
let Str.414 : U8 = 1i64;
|
||||
let Str.415 : U8 = GetTagId Str.401;
|
||||
let Str.416 : Int1 = lowlevel Eq Str.414 Str.415;
|
||||
if Str.416 then
|
||||
let Str.215 : U64 = UnionAtIndex (Id 1) (Index 0) Str.401;
|
||||
let Str.410 : U64 = CallByName Str.36 Str.213;
|
||||
let Str.411 : U64 = CallByName Str.36 Str.214;
|
||||
let Str.409 : U64 = CallByName Num.20 Str.410 Str.411;
|
||||
let Str.216 : U64 = CallByName Num.20 Str.409 Str.215;
|
||||
let Str.408 : U64 = 0i64;
|
||||
inc Str.213;
|
||||
let Str.217 : Str = CallByName Str.37 Str.213 Str.408 Str.215;
|
||||
let Str.406 : U64 = CallByName Str.36 Str.214;
|
||||
let Str.404 : U64 = CallByName Num.51 Str.215 Str.406;
|
||||
let Str.218 : Str = CallByName Str.37 Str.213 Str.404 Str.216;
|
||||
let Str.403 : {Str, Str} = Struct {Str.218, Str.217};
|
||||
let Str.402 : [C {}, C {Str, Str}] = TagId(1) Str.403;
|
||||
ret Str.402;
|
||||
else
|
||||
dec Str.112;
|
||||
let Str.274 : {} = Struct {};
|
||||
let Str.273 : [C {}, C {Str, Str}] = TagId(0) Str.274;
|
||||
ret Str.273;
|
||||
dec Str.213;
|
||||
let Str.413 : {} = Struct {};
|
||||
let Str.412 : [C {}, C {Str, Str}] = TagId(0) Str.413;
|
||||
ret Str.412;
|
||||
|
||||
procedure Str.45 (Str.91, Str.92, Str.93):
|
||||
inc Str.91;
|
||||
let Str.343 : [C {}, C {Str, Str}] = CallByName Str.38 Str.91 Str.92;
|
||||
let Str.351 : U8 = 1i64;
|
||||
let Str.352 : U8 = GetTagId Str.343;
|
||||
let Str.353 : Int1 = lowlevel Eq Str.351 Str.352;
|
||||
if Str.353 then
|
||||
let Str.350 : {Str, Str} = UnionAtIndex (Id 1) (Index 0) Str.343;
|
||||
let Str.95 : Str = StructAtIndex 0 Str.350;
|
||||
let Str.94 : Str = StructAtIndex 1 Str.350;
|
||||
let Str.348 : U64 = CallByName Str.36 Str.91;
|
||||
dec Str.91;
|
||||
let Str.347 : Str = CallByName Str.20 Str.348;
|
||||
let Str.346 : Str = CallByName Str.3 Str.347 Str.94;
|
||||
dec Str.94;
|
||||
let Str.345 : Str = CallByName Str.3 Str.346 Str.93;
|
||||
let Str.344 : Str = CallByName Str.56 Str.345 Str.95 Str.92 Str.93;
|
||||
ret Str.344;
|
||||
procedure Str.45 (Str.192, Str.193, Str.194):
|
||||
inc Str.192;
|
||||
let Str.483 : [C {}, C {Str, Str}] = CallByName Str.38 Str.192 Str.193;
|
||||
let Str.491 : U8 = 1i64;
|
||||
let Str.492 : U8 = GetTagId Str.483;
|
||||
let Str.493 : Int1 = lowlevel Eq Str.491 Str.492;
|
||||
if Str.493 then
|
||||
let Str.490 : {Str, Str} = UnionAtIndex (Id 1) (Index 0) Str.483;
|
||||
let Str.196 : Str = StructAtIndex 0 Str.490;
|
||||
let Str.195 : Str = StructAtIndex 1 Str.490;
|
||||
let Str.488 : U64 = CallByName Str.36 Str.192;
|
||||
dec Str.192;
|
||||
let Str.487 : Str = CallByName Str.20 Str.488;
|
||||
let Str.486 : Str = CallByName Str.3 Str.487 Str.195;
|
||||
dec Str.195;
|
||||
let Str.485 : Str = CallByName Str.3 Str.486 Str.194;
|
||||
let Str.484 : Str = CallByName Str.64 Str.485 Str.196 Str.193 Str.194;
|
||||
ret Str.484;
|
||||
else
|
||||
dec Str.343;
|
||||
ret Str.91;
|
||||
dec Str.483;
|
||||
ret Str.192;
|
||||
|
||||
procedure Str.56 (#Derived_gen.5, #Derived_gen.6, #Derived_gen.7, #Derived_gen.8):
|
||||
joinpoint Str.252 Str.96 Str.97 Str.98 Str.99:
|
||||
inc Str.97;
|
||||
let Str.253 : [C {}, C {Str, Str}] = CallByName Str.38 Str.97 Str.98;
|
||||
let Str.259 : U8 = 1i64;
|
||||
let Str.260 : U8 = GetTagId Str.253;
|
||||
let Str.261 : Int1 = lowlevel Eq Str.259 Str.260;
|
||||
if Str.261 then
|
||||
dec Str.97;
|
||||
let Str.258 : {Str, Str} = UnionAtIndex (Id 1) (Index 0) Str.253;
|
||||
let Str.101 : Str = StructAtIndex 0 Str.258;
|
||||
let Str.100 : Str = StructAtIndex 1 Str.258;
|
||||
let Str.256 : Str = CallByName Str.3 Str.96 Str.100;
|
||||
dec Str.100;
|
||||
let Str.255 : Str = CallByName Str.3 Str.256 Str.99;
|
||||
jump Str.252 Str.255 Str.101 Str.98 Str.99;
|
||||
procedure Str.64 (Bool.24, Bool.25, Bool.26, Bool.27):
|
||||
joinpoint Str.391 Str.197 Str.198 Str.199 Str.200:
|
||||
inc Str.198;
|
||||
let Str.392 : [C {}, C {Str, Str}] = CallByName Str.38 Str.198 Str.199;
|
||||
let Str.398 : U8 = 1i64;
|
||||
let Str.399 : U8 = GetTagId Str.392;
|
||||
let Str.400 : Int1 = lowlevel Eq Str.398 Str.399;
|
||||
if Str.400 then
|
||||
dec Str.198;
|
||||
let Str.397 : {Str, Str} = UnionAtIndex (Id 1) (Index 0) Str.392;
|
||||
let Str.202 : Str = StructAtIndex 0 Str.397;
|
||||
let Str.201 : Str = StructAtIndex 1 Str.397;
|
||||
let Str.395 : Str = CallByName Str.3 Str.197 Str.201;
|
||||
dec Str.201;
|
||||
let Str.394 : Str = CallByName Str.3 Str.395 Str.200;
|
||||
jump Str.391 Str.394 Str.202 Str.199 Str.200;
|
||||
else
|
||||
dec Str.98;
|
||||
dec Str.99;
|
||||
dec Str.253;
|
||||
let Str.257 : Str = CallByName Str.3 Str.96 Str.97;
|
||||
dec Str.97;
|
||||
ret Str.257;
|
||||
dec Str.199;
|
||||
dec Str.392;
|
||||
dec Str.200;
|
||||
let Str.396 : Str = CallByName Str.3 Str.197 Str.198;
|
||||
dec Str.198;
|
||||
ret Str.396;
|
||||
in
|
||||
inc #Derived_gen.7;
|
||||
inc #Derived_gen.8;
|
||||
jump Str.252 #Derived_gen.5 #Derived_gen.6 #Derived_gen.7 #Derived_gen.8;
|
||||
inc Bool.26;
|
||||
inc Bool.27;
|
||||
jump Str.391 Bool.24 Bool.25 Bool.26 Bool.27;
|
||||
|
||||
procedure Str.57 (Str.121, Str.122):
|
||||
let Str.123 : U64 = CallByName Str.36 Str.121;
|
||||
let Str.124 : U64 = CallByName Str.36 Str.122;
|
||||
let Str.125 : U64 = CallByName Num.77 Str.123 Str.124;
|
||||
let Str.279 : U64 = 0i64;
|
||||
let Str.278 : [C , C U64] = CallByName Str.58 Str.121 Str.122 Str.279 Str.125;
|
||||
ret Str.278;
|
||||
procedure Str.65 (Str.222, Str.223):
|
||||
let Str.224 : U64 = CallByName Str.36 Str.222;
|
||||
let Str.225 : U64 = CallByName Str.36 Str.223;
|
||||
let Str.226 : U64 = CallByName Num.77 Str.224 Str.225;
|
||||
let Str.418 : U64 = 0i64;
|
||||
let Str.417 : [C , C U64] = CallByName Str.66 Str.222 Str.223 Str.418 Str.226;
|
||||
ret Str.417;
|
||||
|
||||
procedure Str.58 (#Derived_gen.1, #Derived_gen.2, #Derived_gen.3, #Derived_gen.4):
|
||||
joinpoint Str.280 Str.126 Str.127 Str.128 Str.129:
|
||||
let Str.282 : Int1 = CallByName Num.23 Str.128 Str.129;
|
||||
if Str.282 then
|
||||
let Str.286 : Int1 = CallByName Str.62 Str.126 Str.128 Str.127;
|
||||
if Str.286 then
|
||||
dec Str.127;
|
||||
dec Str.126;
|
||||
let Str.287 : [C , C U64] = TagId(1) Str.128;
|
||||
ret Str.287;
|
||||
procedure Str.66 (Bool.28, Bool.29, Bool.30, Bool.31):
|
||||
joinpoint Str.419 Str.227 Str.228 Str.229 Str.230:
|
||||
let Str.421 : Int1 = CallByName Num.23 Str.229 Str.230;
|
||||
if Str.421 then
|
||||
let Str.425 : Int1 = CallByName Str.70 Str.227 Str.229 Str.228;
|
||||
if Str.425 then
|
||||
dec Str.227;
|
||||
dec Str.228;
|
||||
let Str.426 : [C , C U64] = TagId(1) Str.229;
|
||||
ret Str.426;
|
||||
else
|
||||
let Str.285 : U64 = 1i64;
|
||||
let Str.284 : U64 = CallByName Num.51 Str.128 Str.285;
|
||||
jump Str.280 Str.126 Str.127 Str.284 Str.129;
|
||||
let Str.424 : U64 = 1i64;
|
||||
let Str.423 : U64 = CallByName Num.51 Str.229 Str.424;
|
||||
jump Str.419 Str.227 Str.228 Str.423 Str.230;
|
||||
else
|
||||
dec Str.127;
|
||||
dec Str.126;
|
||||
let Str.281 : [C , C U64] = TagId(0) ;
|
||||
ret Str.281;
|
||||
dec Str.227;
|
||||
dec Str.228;
|
||||
let Str.420 : [C , C U64] = TagId(0) ;
|
||||
ret Str.420;
|
||||
in
|
||||
inc #Derived_gen.1;
|
||||
inc #Derived_gen.2;
|
||||
jump Str.280 #Derived_gen.1 #Derived_gen.2 #Derived_gen.3 #Derived_gen.4;
|
||||
inc Bool.29;
|
||||
inc Bool.28;
|
||||
jump Str.419 Bool.28 Bool.29 Bool.30 Bool.31;
|
||||
|
||||
procedure Str.61 (Str.152, Str.153):
|
||||
let Str.310 : Int1 = CallByName Num.22 Str.152 Str.153;
|
||||
if Str.310 then
|
||||
ret Str.152;
|
||||
procedure Str.69 (Str.253, Str.254):
|
||||
let Str.450 : Int1 = CallByName Num.22 Str.253 Str.254;
|
||||
if Str.450 then
|
||||
ret Str.253;
|
||||
else
|
||||
ret Str.153;
|
||||
ret Str.254;
|
||||
|
||||
procedure Str.62 (Str.154, Str.155, Str.156):
|
||||
let Str.157 : U64 = CallByName Str.36 Str.154;
|
||||
let Str.158 : U64 = CallByName Str.36 Str.156;
|
||||
let Str.308 : U64 = CallByName Num.53 Str.155 Str.158;
|
||||
let Str.159 : U64 = CallByName Str.61 Str.308 Str.157;
|
||||
let Str.307 : U64 = 0i64;
|
||||
inc Str.156;
|
||||
inc Str.154;
|
||||
let Str.289 : {U64, Str, U64, Str, U64, U64} = Struct {Str.159, Str.154, Str.155, Str.156, Str.307, Str.158};
|
||||
let Str.288 : Int1 = CallByName Str.63 Str.289;
|
||||
ret Str.288;
|
||||
procedure Str.70 (Str.255, Str.256, Str.257):
|
||||
let Str.258 : U64 = CallByName Str.36 Str.255;
|
||||
let Str.259 : U64 = CallByName Str.36 Str.257;
|
||||
let Str.448 : U64 = CallByName Num.53 Str.256 Str.259;
|
||||
let Str.260 : U64 = CallByName Str.69 Str.448 Str.258;
|
||||
let Str.447 : U64 = 0i64;
|
||||
inc Str.255;
|
||||
inc Str.257;
|
||||
let Str.428 : {U64, Str, U64, Str, U64, U64} = Struct {Str.260, Str.255, Str.256, Str.257, Str.447, Str.259};
|
||||
let Str.427 : Int1 = CallByName Str.71 Str.428;
|
||||
ret Str.427;
|
||||
|
||||
procedure Str.63 (Str.160):
|
||||
let Str.166 : U64 = StructAtIndex 0 Str.160;
|
||||
let Str.161 : Str = StructAtIndex 1 Str.160;
|
||||
let Str.162 : U64 = StructAtIndex 2 Str.160;
|
||||
let Str.163 : Str = StructAtIndex 3 Str.160;
|
||||
let Str.164 : U64 = StructAtIndex 4 Str.160;
|
||||
let Str.165 : U64 = StructAtIndex 5 Str.160;
|
||||
let Str.167 : Int1 = CallByName Num.25 Str.162 Str.166;
|
||||
if Str.167 then
|
||||
dec Str.163;
|
||||
dec Str.161;
|
||||
let Str.168 : Int1 = CallByName Bool.11 Str.164 Str.165;
|
||||
ret Str.168;
|
||||
procedure Str.71 (Str.261):
|
||||
let Str.267 : U64 = StructAtIndex 0 Str.261;
|
||||
let Str.262 : Str = StructAtIndex 1 Str.261;
|
||||
let Str.263 : U64 = StructAtIndex 2 Str.261;
|
||||
let Str.264 : Str = StructAtIndex 3 Str.261;
|
||||
let Str.265 : U64 = StructAtIndex 4 Str.261;
|
||||
let Str.266 : U64 = StructAtIndex 5 Str.261;
|
||||
let Str.268 : Int1 = CallByName Num.25 Str.263 Str.267;
|
||||
if Str.268 then
|
||||
dec Str.262;
|
||||
dec Str.264;
|
||||
let Str.269 : Int1 = CallByName Bool.9 Str.265 Str.266;
|
||||
ret Str.269;
|
||||
else
|
||||
let Str.303 : U8 = CallByName Str.35 Str.161 Str.162;
|
||||
let Str.304 : U8 = CallByName Str.35 Str.163 Str.164;
|
||||
let Str.169 : Int1 = CallByName Bool.11 Str.303 Str.304;
|
||||
let Str.293 : U64 = StructAtIndex 0 Str.160;
|
||||
let Str.294 : Str = StructAtIndex 1 Str.160;
|
||||
let Str.296 : Str = StructAtIndex 3 Str.160;
|
||||
let Str.298 : U64 = StructAtIndex 5 Str.160;
|
||||
let Str.302 : U64 = 1i64;
|
||||
let Str.300 : U64 = CallByName Num.51 Str.164 Str.302;
|
||||
let Str.301 : U64 = 1i64;
|
||||
let Str.299 : U64 = CallByName Num.51 Str.162 Str.301;
|
||||
let Str.292 : {U64, Str, U64, Str, U64, U64} = Struct {Str.293, Str.294, Str.299, Str.296, Str.300, Str.298};
|
||||
let Str.170 : Int1 = CallByName Str.63 Str.292;
|
||||
let Str.291 : Int1 = CallByName Bool.3 Str.169 Str.170;
|
||||
ret Str.291;
|
||||
let Str.443 : U8 = CallByName Str.35 Str.262 Str.263;
|
||||
let Str.444 : U8 = CallByName Str.35 Str.264 Str.265;
|
||||
let Str.270 : Int1 = CallByName Bool.9 Str.443 Str.444;
|
||||
let Str.433 : U64 = StructAtIndex 0 Str.261;
|
||||
let Str.434 : Str = StructAtIndex 1 Str.261;
|
||||
let Str.436 : Str = StructAtIndex 3 Str.261;
|
||||
let Str.438 : U64 = StructAtIndex 5 Str.261;
|
||||
let Str.442 : U64 = 1i64;
|
||||
let Str.440 : U64 = CallByName Num.51 Str.265 Str.442;
|
||||
let Str.441 : U64 = 1i64;
|
||||
let Str.439 : U64 = CallByName Num.51 Str.263 Str.441;
|
||||
let Str.432 : {U64, Str, U64, Str, U64, U64} = Struct {Str.433, Str.434, Str.439, Str.436, Str.440, Str.438};
|
||||
let Str.271 : Int1 = CallByName Str.71 Str.432;
|
||||
if Str.270 then
|
||||
ret Str.271;
|
||||
else
|
||||
let Str.430 : Int1 = CallByName Bool.1;
|
||||
ret Str.430;
|
||||
|
||||
procedure Test.0 ():
|
||||
let Test.5 : Str = "Hello ";
|
||||
let Test.2 : Str = "world";
|
||||
inc Test.2;
|
||||
let Test.3 : Str = CallByName Inspect.33 Test.2;
|
||||
dbg Test.3;
|
||||
dec Test.3;
|
||||
let Test.8 : Str = "!";
|
||||
let Test.6 : Str = CallByName Str.3 Test.2 Test.8;
|
||||
dec Test.8;
|
||||
let Test.4 : Str = CallByName Str.3 Test.5 Test.6;
|
||||
dec Test.6;
|
||||
ret Test.4;
|
||||
let Test.4 : Str = "Hello ";
|
||||
let Test.1 : Str = "world";
|
||||
inc Test.1;
|
||||
let Test.2 : Str = CallByName Inspect.33 Test.1;
|
||||
dbg Test.2;
|
||||
dec Test.2;
|
||||
let Test.7 : Str = "!";
|
||||
let Test.5 : Str = CallByName Str.3 Test.1 Test.7;
|
||||
dec Test.7;
|
||||
let Test.3 : Str = CallByName Str.3 Test.4 Test.5;
|
||||
dec Test.5;
|
||||
ret Test.3;
|
||||
|
|
|
@ -39,18 +39,18 @@ procedure Num.96 (#Attr.2):
|
|||
ret Num.283;
|
||||
|
||||
procedure Str.3 (#Attr.2, #Attr.3):
|
||||
let Str.246 : Str = lowlevel StrConcat #Attr.2 #Attr.3;
|
||||
ret Str.246;
|
||||
let Str.385 : Str = lowlevel StrConcat #Attr.2 #Attr.3;
|
||||
ret Str.385;
|
||||
|
||||
procedure Test.0 ():
|
||||
let Test.6 : I64 = 1i64;
|
||||
let Test.7 : Str = CallByName Inspect.33 Test.6;
|
||||
dbg Test.7;
|
||||
dec Test.7;
|
||||
let Test.8 : Str = CallByName Inspect.33 Test.6;
|
||||
dbg Test.8;
|
||||
dec Test.8;
|
||||
let Test.9 : Str = CallByName Inspect.33 Test.6;
|
||||
dbg Test.9;
|
||||
dec Test.9;
|
||||
ret Test.6;
|
||||
let Test.3 : I64 = 1i64;
|
||||
let Test.4 : Str = CallByName Inspect.33 Test.3;
|
||||
dbg Test.4;
|
||||
dec Test.4;
|
||||
let Test.5 : Str = CallByName Inspect.33 Test.3;
|
||||
dbg Test.5;
|
||||
dec Test.5;
|
||||
let Test.6 : Str = CallByName Inspect.33 Test.3;
|
||||
dbg Test.6;
|
||||
dec Test.6;
|
||||
ret Test.3;
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
procedure Bool.11 (#Attr.2, #Attr.3):
|
||||
let Bool.24 : Int1 = lowlevel Eq #Attr.2 #Attr.3;
|
||||
ret Bool.24;
|
||||
procedure Bool.1 ():
|
||||
let Bool.21 : Int1 = false;
|
||||
ret Bool.21;
|
||||
|
||||
procedure Bool.11 (#Attr.2, #Attr.3):
|
||||
let Bool.25 : Int1 = lowlevel Eq #Attr.2 #Attr.3;
|
||||
ret Bool.25;
|
||||
procedure Bool.9 (#Attr.2, #Attr.3):
|
||||
let Bool.22 : Int1 = lowlevel Eq #Attr.2 #Attr.3;
|
||||
ret Bool.22;
|
||||
|
||||
procedure Bool.3 (#Attr.2, #Attr.3):
|
||||
let Bool.23 : Int1 = lowlevel And #Attr.2 #Attr.3;
|
||||
procedure Bool.9 (#Attr.2, #Attr.3):
|
||||
let Bool.23 : Int1 = lowlevel Eq #Attr.2 #Attr.3;
|
||||
ret Bool.23;
|
||||
|
||||
procedure Inspect.245 (Inspect.246, Inspect.244):
|
||||
|
@ -100,181 +100,184 @@ procedure Num.77 (#Attr.2, #Attr.3):
|
|||
ret Num.293;
|
||||
|
||||
procedure Str.20 (#Attr.2):
|
||||
let Str.313 : Str = lowlevel StrWithCapacity #Attr.2;
|
||||
ret Str.313;
|
||||
let Str.453 : Str = lowlevel StrWithCapacity #Attr.2;
|
||||
ret Str.453;
|
||||
|
||||
procedure Str.3 (#Attr.2, #Attr.3):
|
||||
let Str.246 : Str = lowlevel StrConcat #Attr.2 #Attr.3;
|
||||
ret Str.246;
|
||||
let Str.385 : Str = lowlevel StrConcat #Attr.2 #Attr.3;
|
||||
ret Str.385;
|
||||
|
||||
procedure Str.35 (#Attr.2, #Attr.3):
|
||||
let Str.303 : U8 = lowlevel StrGetUnsafe #Attr.2 #Attr.3;
|
||||
ret Str.303;
|
||||
let Str.443 : U8 = lowlevel StrGetUnsafe #Attr.2 #Attr.3;
|
||||
ret Str.443;
|
||||
|
||||
procedure Str.36 (#Attr.2):
|
||||
let Str.266 : U64 = lowlevel StrCountUtf8Bytes #Attr.2;
|
||||
ret Str.266;
|
||||
let Str.405 : U64 = lowlevel StrCountUtf8Bytes #Attr.2;
|
||||
ret Str.405;
|
||||
|
||||
procedure Str.37 (#Attr.2, #Attr.3, #Attr.4):
|
||||
let Str.264 : Str = lowlevel StrSubstringUnsafe #Attr.2 #Attr.3 #Attr.4;
|
||||
ret Str.264;
|
||||
let Str.403 : Str = lowlevel StrSubstringUnsafe #Attr.2 #Attr.3 #Attr.4;
|
||||
ret Str.403;
|
||||
|
||||
procedure Str.38 (Str.112, Str.113):
|
||||
let Str.260 : [C , C U64] = CallByName Str.57 Str.112 Str.113;
|
||||
let Str.273 : U8 = 1i64;
|
||||
let Str.274 : U8 = GetTagId Str.260;
|
||||
let Str.275 : Int1 = lowlevel Eq Str.273 Str.274;
|
||||
if Str.275 then
|
||||
let Str.114 : U64 = UnionAtIndex (Id 1) (Index 0) Str.260;
|
||||
let Str.269 : U64 = CallByName Str.36 Str.112;
|
||||
let Str.270 : U64 = CallByName Str.36 Str.113;
|
||||
let Str.268 : U64 = CallByName Num.20 Str.269 Str.270;
|
||||
let Str.115 : U64 = CallByName Num.20 Str.268 Str.114;
|
||||
let Str.267 : U64 = 0i64;
|
||||
inc Str.112;
|
||||
let Str.116 : Str = CallByName Str.37 Str.112 Str.267 Str.114;
|
||||
let Str.265 : U64 = CallByName Str.36 Str.113;
|
||||
let Str.263 : U64 = CallByName Num.51 Str.114 Str.265;
|
||||
let Str.117 : Str = CallByName Str.37 Str.112 Str.263 Str.115;
|
||||
let Str.262 : {Str, Str} = Struct {Str.117, Str.116};
|
||||
let Str.261 : [C {}, C {Str, Str}] = TagId(1) Str.262;
|
||||
ret Str.261;
|
||||
procedure Str.38 (Str.213, Str.214):
|
||||
let Str.399 : [C , C U64] = CallByName Str.65 Str.213 Str.214;
|
||||
let Str.412 : U8 = 1i64;
|
||||
let Str.413 : U8 = GetTagId Str.399;
|
||||
let Str.414 : Int1 = lowlevel Eq Str.412 Str.413;
|
||||
if Str.414 then
|
||||
let Str.215 : U64 = UnionAtIndex (Id 1) (Index 0) Str.399;
|
||||
let Str.408 : U64 = CallByName Str.36 Str.213;
|
||||
let Str.409 : U64 = CallByName Str.36 Str.214;
|
||||
let Str.407 : U64 = CallByName Num.20 Str.408 Str.409;
|
||||
let Str.216 : U64 = CallByName Num.20 Str.407 Str.215;
|
||||
let Str.406 : U64 = 0i64;
|
||||
inc Str.213;
|
||||
let Str.217 : Str = CallByName Str.37 Str.213 Str.406 Str.215;
|
||||
let Str.404 : U64 = CallByName Str.36 Str.214;
|
||||
let Str.402 : U64 = CallByName Num.51 Str.215 Str.404;
|
||||
let Str.218 : Str = CallByName Str.37 Str.213 Str.402 Str.216;
|
||||
let Str.401 : {Str, Str} = Struct {Str.218, Str.217};
|
||||
let Str.400 : [C {}, C {Str, Str}] = TagId(1) Str.401;
|
||||
ret Str.400;
|
||||
else
|
||||
dec Str.112;
|
||||
let Str.272 : {} = Struct {};
|
||||
let Str.271 : [C {}, C {Str, Str}] = TagId(0) Str.272;
|
||||
ret Str.271;
|
||||
dec Str.213;
|
||||
let Str.411 : {} = Struct {};
|
||||
let Str.410 : [C {}, C {Str, Str}] = TagId(0) Str.411;
|
||||
ret Str.410;
|
||||
|
||||
procedure Str.45 (Str.91, Str.92, Str.93):
|
||||
inc Str.91;
|
||||
let Str.341 : [C {}, C {Str, Str}] = CallByName Str.38 Str.91 Str.92;
|
||||
let Str.349 : U8 = 1i64;
|
||||
let Str.350 : U8 = GetTagId Str.341;
|
||||
let Str.351 : Int1 = lowlevel Eq Str.349 Str.350;
|
||||
if Str.351 then
|
||||
let Str.348 : {Str, Str} = UnionAtIndex (Id 1) (Index 0) Str.341;
|
||||
let Str.95 : Str = StructAtIndex 0 Str.348;
|
||||
let Str.94 : Str = StructAtIndex 1 Str.348;
|
||||
let Str.346 : U64 = CallByName Str.36 Str.91;
|
||||
dec Str.91;
|
||||
let Str.345 : Str = CallByName Str.20 Str.346;
|
||||
let Str.344 : Str = CallByName Str.3 Str.345 Str.94;
|
||||
dec Str.94;
|
||||
let Str.343 : Str = CallByName Str.3 Str.344 Str.93;
|
||||
let Str.342 : Str = CallByName Str.56 Str.343 Str.95 Str.92 Str.93;
|
||||
ret Str.342;
|
||||
procedure Str.45 (Str.192, Str.193, Str.194):
|
||||
inc Str.192;
|
||||
let Str.481 : [C {}, C {Str, Str}] = CallByName Str.38 Str.192 Str.193;
|
||||
let Str.489 : U8 = 1i64;
|
||||
let Str.490 : U8 = GetTagId Str.481;
|
||||
let Str.491 : Int1 = lowlevel Eq Str.489 Str.490;
|
||||
if Str.491 then
|
||||
let Str.488 : {Str, Str} = UnionAtIndex (Id 1) (Index 0) Str.481;
|
||||
let Str.196 : Str = StructAtIndex 0 Str.488;
|
||||
let Str.195 : Str = StructAtIndex 1 Str.488;
|
||||
let Str.486 : U64 = CallByName Str.36 Str.192;
|
||||
dec Str.192;
|
||||
let Str.485 : Str = CallByName Str.20 Str.486;
|
||||
let Str.484 : Str = CallByName Str.3 Str.485 Str.195;
|
||||
dec Str.195;
|
||||
let Str.483 : Str = CallByName Str.3 Str.484 Str.194;
|
||||
let Str.482 : Str = CallByName Str.64 Str.483 Str.196 Str.193 Str.194;
|
||||
ret Str.482;
|
||||
else
|
||||
dec Str.341;
|
||||
ret Str.91;
|
||||
dec Str.481;
|
||||
ret Str.192;
|
||||
|
||||
procedure Str.56 (#Derived_gen.5, #Derived_gen.6, #Derived_gen.7, #Derived_gen.8):
|
||||
joinpoint Str.250 Str.96 Str.97 Str.98 Str.99:
|
||||
inc Str.97;
|
||||
let Str.251 : [C {}, C {Str, Str}] = CallByName Str.38 Str.97 Str.98;
|
||||
let Str.257 : U8 = 1i64;
|
||||
let Str.258 : U8 = GetTagId Str.251;
|
||||
let Str.259 : Int1 = lowlevel Eq Str.257 Str.258;
|
||||
if Str.259 then
|
||||
dec Str.97;
|
||||
let Str.256 : {Str, Str} = UnionAtIndex (Id 1) (Index 0) Str.251;
|
||||
let Str.101 : Str = StructAtIndex 0 Str.256;
|
||||
let Str.100 : Str = StructAtIndex 1 Str.256;
|
||||
let Str.254 : Str = CallByName Str.3 Str.96 Str.100;
|
||||
dec Str.100;
|
||||
let Str.253 : Str = CallByName Str.3 Str.254 Str.99;
|
||||
jump Str.250 Str.253 Str.101 Str.98 Str.99;
|
||||
procedure Str.64 (Bool.24, Bool.25, Bool.26, Bool.27):
|
||||
joinpoint Str.389 Str.197 Str.198 Str.199 Str.200:
|
||||
inc Str.198;
|
||||
let Str.390 : [C {}, C {Str, Str}] = CallByName Str.38 Str.198 Str.199;
|
||||
let Str.396 : U8 = 1i64;
|
||||
let Str.397 : U8 = GetTagId Str.390;
|
||||
let Str.398 : Int1 = lowlevel Eq Str.396 Str.397;
|
||||
if Str.398 then
|
||||
dec Str.198;
|
||||
let Str.395 : {Str, Str} = UnionAtIndex (Id 1) (Index 0) Str.390;
|
||||
let Str.202 : Str = StructAtIndex 0 Str.395;
|
||||
let Str.201 : Str = StructAtIndex 1 Str.395;
|
||||
let Str.393 : Str = CallByName Str.3 Str.197 Str.201;
|
||||
dec Str.201;
|
||||
let Str.392 : Str = CallByName Str.3 Str.393 Str.200;
|
||||
jump Str.389 Str.392 Str.202 Str.199 Str.200;
|
||||
else
|
||||
dec Str.98;
|
||||
dec Str.251;
|
||||
dec Str.99;
|
||||
let Str.255 : Str = CallByName Str.3 Str.96 Str.97;
|
||||
dec Str.97;
|
||||
ret Str.255;
|
||||
dec Str.199;
|
||||
dec Str.390;
|
||||
dec Str.200;
|
||||
let Str.394 : Str = CallByName Str.3 Str.197 Str.198;
|
||||
dec Str.198;
|
||||
ret Str.394;
|
||||
in
|
||||
inc #Derived_gen.7;
|
||||
inc #Derived_gen.8;
|
||||
jump Str.250 #Derived_gen.5 #Derived_gen.6 #Derived_gen.7 #Derived_gen.8;
|
||||
inc Bool.26;
|
||||
inc Bool.27;
|
||||
jump Str.389 Bool.24 Bool.25 Bool.26 Bool.27;
|
||||
|
||||
procedure Str.57 (Str.121, Str.122):
|
||||
let Str.123 : U64 = CallByName Str.36 Str.121;
|
||||
let Str.124 : U64 = CallByName Str.36 Str.122;
|
||||
let Str.125 : U64 = CallByName Num.77 Str.123 Str.124;
|
||||
let Str.277 : U64 = 0i64;
|
||||
let Str.276 : [C , C U64] = CallByName Str.58 Str.121 Str.122 Str.277 Str.125;
|
||||
ret Str.276;
|
||||
procedure Str.65 (Str.222, Str.223):
|
||||
let Str.224 : U64 = CallByName Str.36 Str.222;
|
||||
let Str.225 : U64 = CallByName Str.36 Str.223;
|
||||
let Str.226 : U64 = CallByName Num.77 Str.224 Str.225;
|
||||
let Str.416 : U64 = 0i64;
|
||||
let Str.415 : [C , C U64] = CallByName Str.66 Str.222 Str.223 Str.416 Str.226;
|
||||
ret Str.415;
|
||||
|
||||
procedure Str.58 (#Derived_gen.1, #Derived_gen.2, #Derived_gen.3, #Derived_gen.4):
|
||||
joinpoint Str.278 Str.126 Str.127 Str.128 Str.129:
|
||||
let Str.280 : Int1 = CallByName Num.23 Str.128 Str.129;
|
||||
if Str.280 then
|
||||
let Str.284 : Int1 = CallByName Str.62 Str.126 Str.128 Str.127;
|
||||
if Str.284 then
|
||||
dec Str.127;
|
||||
dec Str.126;
|
||||
let Str.285 : [C , C U64] = TagId(1) Str.128;
|
||||
ret Str.285;
|
||||
procedure Str.66 (Bool.28, Bool.29, Bool.30, Bool.31):
|
||||
joinpoint Str.417 Str.227 Str.228 Str.229 Str.230:
|
||||
let Str.419 : Int1 = CallByName Num.23 Str.229 Str.230;
|
||||
if Str.419 then
|
||||
let Str.423 : Int1 = CallByName Str.70 Str.227 Str.229 Str.228;
|
||||
if Str.423 then
|
||||
dec Str.227;
|
||||
dec Str.228;
|
||||
let Str.424 : [C , C U64] = TagId(1) Str.229;
|
||||
ret Str.424;
|
||||
else
|
||||
let Str.283 : U64 = 1i64;
|
||||
let Str.282 : U64 = CallByName Num.51 Str.128 Str.283;
|
||||
jump Str.278 Str.126 Str.127 Str.282 Str.129;
|
||||
let Str.422 : U64 = 1i64;
|
||||
let Str.421 : U64 = CallByName Num.51 Str.229 Str.422;
|
||||
jump Str.417 Str.227 Str.228 Str.421 Str.230;
|
||||
else
|
||||
dec Str.127;
|
||||
dec Str.126;
|
||||
let Str.279 : [C , C U64] = TagId(0) ;
|
||||
ret Str.279;
|
||||
dec Str.227;
|
||||
dec Str.228;
|
||||
let Str.418 : [C , C U64] = TagId(0) ;
|
||||
ret Str.418;
|
||||
in
|
||||
inc #Derived_gen.1;
|
||||
inc #Derived_gen.2;
|
||||
jump Str.278 #Derived_gen.1 #Derived_gen.2 #Derived_gen.3 #Derived_gen.4;
|
||||
inc Bool.29;
|
||||
inc Bool.28;
|
||||
jump Str.417 Bool.28 Bool.29 Bool.30 Bool.31;
|
||||
|
||||
procedure Str.61 (Str.152, Str.153):
|
||||
let Str.308 : Int1 = CallByName Num.22 Str.152 Str.153;
|
||||
if Str.308 then
|
||||
ret Str.152;
|
||||
procedure Str.69 (Str.253, Str.254):
|
||||
let Str.448 : Int1 = CallByName Num.22 Str.253 Str.254;
|
||||
if Str.448 then
|
||||
ret Str.253;
|
||||
else
|
||||
ret Str.153;
|
||||
ret Str.254;
|
||||
|
||||
procedure Str.62 (Str.154, Str.155, Str.156):
|
||||
let Str.157 : U64 = CallByName Str.36 Str.154;
|
||||
let Str.158 : U64 = CallByName Str.36 Str.156;
|
||||
let Str.306 : U64 = CallByName Num.53 Str.155 Str.158;
|
||||
let Str.159 : U64 = CallByName Str.61 Str.306 Str.157;
|
||||
let Str.305 : U64 = 0i64;
|
||||
inc Str.156;
|
||||
inc Str.154;
|
||||
let Str.287 : {U64, Str, U64, Str, U64, U64} = Struct {Str.159, Str.154, Str.155, Str.156, Str.305, Str.158};
|
||||
let Str.286 : Int1 = CallByName Str.63 Str.287;
|
||||
ret Str.286;
|
||||
procedure Str.70 (Str.255, Str.256, Str.257):
|
||||
let Str.258 : U64 = CallByName Str.36 Str.255;
|
||||
let Str.259 : U64 = CallByName Str.36 Str.257;
|
||||
let Str.446 : U64 = CallByName Num.53 Str.256 Str.259;
|
||||
let Str.260 : U64 = CallByName Str.69 Str.446 Str.258;
|
||||
let Str.445 : U64 = 0i64;
|
||||
inc Str.255;
|
||||
inc Str.257;
|
||||
let Str.426 : {U64, Str, U64, Str, U64, U64} = Struct {Str.260, Str.255, Str.256, Str.257, Str.445, Str.259};
|
||||
let Str.425 : Int1 = CallByName Str.71 Str.426;
|
||||
ret Str.425;
|
||||
|
||||
procedure Str.63 (Str.160):
|
||||
let Str.166 : U64 = StructAtIndex 0 Str.160;
|
||||
let Str.161 : Str = StructAtIndex 1 Str.160;
|
||||
let Str.162 : U64 = StructAtIndex 2 Str.160;
|
||||
let Str.163 : Str = StructAtIndex 3 Str.160;
|
||||
let Str.164 : U64 = StructAtIndex 4 Str.160;
|
||||
let Str.165 : U64 = StructAtIndex 5 Str.160;
|
||||
let Str.167 : Int1 = CallByName Num.25 Str.162 Str.166;
|
||||
if Str.167 then
|
||||
dec Str.163;
|
||||
dec Str.161;
|
||||
let Str.168 : Int1 = CallByName Bool.11 Str.164 Str.165;
|
||||
ret Str.168;
|
||||
procedure Str.71 (Str.261):
|
||||
let Str.267 : U64 = StructAtIndex 0 Str.261;
|
||||
let Str.262 : Str = StructAtIndex 1 Str.261;
|
||||
let Str.263 : U64 = StructAtIndex 2 Str.261;
|
||||
let Str.264 : Str = StructAtIndex 3 Str.261;
|
||||
let Str.265 : U64 = StructAtIndex 4 Str.261;
|
||||
let Str.266 : U64 = StructAtIndex 5 Str.261;
|
||||
let Str.268 : Int1 = CallByName Num.25 Str.263 Str.267;
|
||||
if Str.268 then
|
||||
dec Str.262;
|
||||
dec Str.264;
|
||||
let Str.269 : Int1 = CallByName Bool.9 Str.265 Str.266;
|
||||
ret Str.269;
|
||||
else
|
||||
let Str.301 : U8 = CallByName Str.35 Str.161 Str.162;
|
||||
let Str.302 : U8 = CallByName Str.35 Str.163 Str.164;
|
||||
let Str.169 : Int1 = CallByName Bool.11 Str.301 Str.302;
|
||||
let Str.291 : U64 = StructAtIndex 0 Str.160;
|
||||
let Str.292 : Str = StructAtIndex 1 Str.160;
|
||||
let Str.294 : Str = StructAtIndex 3 Str.160;
|
||||
let Str.296 : U64 = StructAtIndex 5 Str.160;
|
||||
let Str.300 : U64 = 1i64;
|
||||
let Str.298 : U64 = CallByName Num.51 Str.164 Str.300;
|
||||
let Str.299 : U64 = 1i64;
|
||||
let Str.297 : U64 = CallByName Num.51 Str.162 Str.299;
|
||||
let Str.290 : {U64, Str, U64, Str, U64, U64} = Struct {Str.291, Str.292, Str.297, Str.294, Str.298, Str.296};
|
||||
let Str.170 : Int1 = CallByName Str.63 Str.290;
|
||||
let Str.289 : Int1 = CallByName Bool.3 Str.169 Str.170;
|
||||
ret Str.289;
|
||||
let Str.441 : U8 = CallByName Str.35 Str.262 Str.263;
|
||||
let Str.442 : U8 = CallByName Str.35 Str.264 Str.265;
|
||||
let Str.270 : Int1 = CallByName Bool.9 Str.441 Str.442;
|
||||
let Str.431 : U64 = StructAtIndex 0 Str.261;
|
||||
let Str.432 : Str = StructAtIndex 1 Str.261;
|
||||
let Str.434 : Str = StructAtIndex 3 Str.261;
|
||||
let Str.436 : U64 = StructAtIndex 5 Str.261;
|
||||
let Str.440 : U64 = 1i64;
|
||||
let Str.438 : U64 = CallByName Num.51 Str.265 Str.440;
|
||||
let Str.439 : U64 = 1i64;
|
||||
let Str.437 : U64 = CallByName Num.51 Str.263 Str.439;
|
||||
let Str.430 : {U64, Str, U64, Str, U64, U64} = Struct {Str.431, Str.432, Str.437, Str.434, Str.438, Str.436};
|
||||
let Str.271 : Int1 = CallByName Str.71 Str.430;
|
||||
if Str.270 then
|
||||
ret Str.271;
|
||||
else
|
||||
let Str.428 : Int1 = CallByName Bool.1;
|
||||
ret Str.428;
|
||||
|
||||
procedure Test.0 ():
|
||||
let Test.3 : Str = "";
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
procedure Bool.11 (#Attr.2, #Attr.3):
|
||||
let Bool.24 : Int1 = lowlevel Eq #Attr.2 #Attr.3;
|
||||
ret Bool.24;
|
||||
procedure Bool.9 (#Attr.2, #Attr.3):
|
||||
let Bool.22 : Int1 = lowlevel Eq #Attr.2 #Attr.3;
|
||||
ret Bool.22;
|
||||
|
||||
procedure Num.19 (#Attr.2, #Attr.3):
|
||||
let Num.285 : I64 = lowlevel NumAdd #Attr.2 #Attr.3;
|
||||
|
@ -11,8 +11,8 @@ procedure Num.96 (#Attr.2):
|
|||
ret Num.284;
|
||||
|
||||
procedure Str.3 (#Attr.2, #Attr.3):
|
||||
let Str.247 : Str = lowlevel StrConcat #Attr.2 #Attr.3;
|
||||
ret Str.247;
|
||||
let Str.386 : Str = lowlevel StrConcat #Attr.2 #Attr.3;
|
||||
ret Str.386;
|
||||
|
||||
procedure Test.1 (Test.2):
|
||||
let Test.3 : Str = CallByName Num.96 Test.2;
|
||||
|
@ -25,7 +25,7 @@ procedure Test.1 (Test.2):
|
|||
ret Test.8;
|
||||
in
|
||||
let Test.22 : I64 = 1i64;
|
||||
let Test.20 : Int1 = CallByName Bool.11 Test.2 Test.22;
|
||||
let Test.20 : Int1 = CallByName Bool.9 Test.2 Test.22;
|
||||
if Test.20 then
|
||||
dec Test.3;
|
||||
let Test.21 : Str = "early 1";
|
||||
|
@ -38,7 +38,7 @@ procedure Test.1 (Test.2):
|
|||
jump Test.12 Test.11;
|
||||
in
|
||||
let Test.17 : I64 = 2i64;
|
||||
let Test.15 : Int1 = CallByName Bool.11 Test.2 Test.17;
|
||||
let Test.15 : Int1 = CallByName Bool.9 Test.2 Test.17;
|
||||
if Test.15 then
|
||||
dec Test.3;
|
||||
dec Test.5;
|
||||
|
|
4
crates/compiler/test_mono/generated/dict.txt
generated
4
crates/compiler/test_mono/generated/dict.txt
generated
|
@ -9,8 +9,8 @@ procedure Dict.1 (Dict.732):
|
|||
|
||||
procedure Dict.4 (Dict.738):
|
||||
let Dict.163 : List {[], []} = StructAtIndex 1 Dict.738;
|
||||
let #Derived_gen.0 : List {U32, U32} = StructAtIndex 0 Dict.738;
|
||||
dec #Derived_gen.0;
|
||||
let Bool.21 : List {U32, U32} = StructAtIndex 0 Dict.738;
|
||||
dec Bool.21;
|
||||
let Dict.739 : U64 = CallByName List.6 Dict.163;
|
||||
dec Dict.163;
|
||||
ret Dict.739;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
procedure Bool.2 ():
|
||||
let Bool.23 : Int1 = true;
|
||||
ret Bool.23;
|
||||
let Bool.21 : Int1 = true;
|
||||
ret Bool.21;
|
||||
|
||||
procedure Test.2 (Test.5):
|
||||
let Test.6 : Int1 = CallByName Bool.2;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
procedure Bool.2 ():
|
||||
let Bool.23 : Int1 = true;
|
||||
ret Bool.23;
|
||||
let Bool.21 : Int1 = true;
|
||||
ret Bool.21;
|
||||
|
||||
procedure Test.2 (Test.5):
|
||||
let Test.6 : Int1 = CallByName Bool.2;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
procedure Bool.1 ():
|
||||
let Bool.23 : Int1 = false;
|
||||
ret Bool.23;
|
||||
let Bool.21 : Int1 = false;
|
||||
ret Bool.21;
|
||||
|
||||
procedure List.2 (List.120, List.121):
|
||||
let List.681 : U64 = CallByName List.6 List.120;
|
||||
|
|
|
@ -67,7 +67,7 @@ procedure Encode.26 (Encode.107, Encode.108):
|
|||
let Encode.110 : List U8 = CallByName Encode.24 Encode.111 Encode.112 Encode.108;
|
||||
ret Encode.110;
|
||||
|
||||
procedure List.101 (#Derived_gen.26, #Derived_gen.27, #Derived_gen.28, #Derived_gen.29, #Derived_gen.30):
|
||||
procedure List.101 (#Derived_gen.35, #Derived_gen.36, #Derived_gen.37, #Derived_gen.38, #Derived_gen.39):
|
||||
joinpoint List.678 List.175 List.176 List.177 List.178 List.179:
|
||||
let List.680 : Int1 = CallByName Num.22 List.178 List.179;
|
||||
if List.680 then
|
||||
|
@ -81,10 +81,10 @@ procedure List.101 (#Derived_gen.26, #Derived_gen.27, #Derived_gen.28, #Derived_
|
|||
dec List.175;
|
||||
ret List.176;
|
||||
in
|
||||
inc #Derived_gen.26;
|
||||
jump List.678 #Derived_gen.26 #Derived_gen.27 #Derived_gen.28 #Derived_gen.29 #Derived_gen.30;
|
||||
inc #Derived_gen.35;
|
||||
jump List.678 #Derived_gen.35 #Derived_gen.36 #Derived_gen.37 #Derived_gen.38 #Derived_gen.39;
|
||||
|
||||
procedure List.101 (#Derived_gen.31, #Derived_gen.32, #Derived_gen.33, #Derived_gen.34, #Derived_gen.35):
|
||||
procedure List.101 (#Derived_gen.40, #Derived_gen.41, #Derived_gen.42, #Derived_gen.43, #Derived_gen.44):
|
||||
joinpoint List.704 List.175 List.176 List.177 List.178 List.179:
|
||||
let List.706 : Int1 = CallByName Num.22 List.178 List.179;
|
||||
if List.706 then
|
||||
|
@ -98,8 +98,8 @@ procedure List.101 (#Derived_gen.31, #Derived_gen.32, #Derived_gen.33, #Derived_
|
|||
dec List.175;
|
||||
ret List.176;
|
||||
in
|
||||
inc #Derived_gen.31;
|
||||
jump List.704 #Derived_gen.31 #Derived_gen.32 #Derived_gen.33 #Derived_gen.34 #Derived_gen.35;
|
||||
inc #Derived_gen.40;
|
||||
jump List.704 #Derived_gen.40 #Derived_gen.41 #Derived_gen.42 #Derived_gen.43 #Derived_gen.44;
|
||||
|
||||
procedure List.18 (List.172, List.173, List.174):
|
||||
let List.676 : U64 = 0i64;
|
||||
|
@ -164,32 +164,32 @@ procedure Num.96 (#Attr.2):
|
|||
ret Num.287;
|
||||
|
||||
procedure Str.12 (#Attr.2):
|
||||
let Str.259 : List U8 = lowlevel StrToUtf8 #Attr.2;
|
||||
ret Str.259;
|
||||
let Str.398 : List U8 = lowlevel StrToUtf8 #Attr.2;
|
||||
ret Str.398;
|
||||
|
||||
procedure Str.36 (#Attr.2):
|
||||
let Str.260 : U64 = lowlevel StrCountUtf8Bytes #Attr.2;
|
||||
ret Str.260;
|
||||
let Str.399 : U64 = lowlevel StrCountUtf8Bytes #Attr.2;
|
||||
ret Str.399;
|
||||
|
||||
procedure Str.43 (#Attr.2):
|
||||
let Str.254 : {U64, Str, Int1, U8} = lowlevel StrFromUtf8 #Attr.2;
|
||||
ret Str.254;
|
||||
let Str.393 : {U64, Str, Int1, U8} = lowlevel StrFromUtf8 #Attr.2;
|
||||
ret Str.393;
|
||||
|
||||
procedure Str.9 (Str.73):
|
||||
let Str.74 : {U64, Str, Int1, U8} = CallByName Str.43 Str.73;
|
||||
let Str.251 : Int1 = StructAtIndex 2 Str.74;
|
||||
if Str.251 then
|
||||
let Str.253 : Str = StructAtIndex 1 Str.74;
|
||||
let Str.252 : [C {U64, U8}, C Str] = TagId(1) Str.253;
|
||||
ret Str.252;
|
||||
procedure Str.9 (Str.79):
|
||||
let Str.80 : {U64, Str, Int1, U8} = CallByName Str.43 Str.79;
|
||||
let Str.390 : Int1 = StructAtIndex 2 Str.80;
|
||||
if Str.390 then
|
||||
let Str.392 : Str = StructAtIndex 1 Str.80;
|
||||
let Str.391 : [C {U64, U8}, C Str] = TagId(1) Str.392;
|
||||
ret Str.391;
|
||||
else
|
||||
let Str.249 : U64 = StructAtIndex 0 Str.74;
|
||||
let Str.250 : U8 = StructAtIndex 3 Str.74;
|
||||
let #Derived_gen.45 : Str = StructAtIndex 1 Str.74;
|
||||
let Str.388 : U64 = StructAtIndex 0 Str.80;
|
||||
let Str.389 : U8 = StructAtIndex 3 Str.80;
|
||||
let #Derived_gen.45 : Str = StructAtIndex 1 Str.80;
|
||||
dec #Derived_gen.45;
|
||||
let Str.248 : {U64, U8} = Struct {Str.249, Str.250};
|
||||
let Str.246 : [C {U64, U8}, C Str] = TagId(0) Str.248;
|
||||
ret Str.246;
|
||||
let Str.387 : {U64, U8} = Struct {Str.388, Str.389};
|
||||
let Str.385 : [C {U64, U8}, C Str] = TagId(0) Str.387;
|
||||
ret Str.385;
|
||||
|
||||
procedure Test.20 (Test.56):
|
||||
let Test.325 : Str = CallByName Encode.23 Test.56;
|
||||
|
|
|
@ -39,7 +39,7 @@ procedure Encode.26 (Encode.107, Encode.108):
|
|||
let Encode.110 : List U8 = CallByName Encode.24 Encode.111 Encode.112 Encode.108;
|
||||
ret Encode.110;
|
||||
|
||||
procedure List.101 (#Derived_gen.16, #Derived_gen.17, #Derived_gen.18, #Derived_gen.19, #Derived_gen.20):
|
||||
procedure List.101 (#Derived_gen.19, #Derived_gen.20, #Derived_gen.21, #Derived_gen.22, #Derived_gen.23):
|
||||
joinpoint List.678 List.175 List.176 List.177 List.178 List.179:
|
||||
let List.680 : Int1 = CallByName Num.22 List.178 List.179;
|
||||
if List.680 then
|
||||
|
@ -53,8 +53,8 @@ procedure List.101 (#Derived_gen.16, #Derived_gen.17, #Derived_gen.18, #Derived_
|
|||
dec List.175;
|
||||
ret List.176;
|
||||
in
|
||||
inc #Derived_gen.16;
|
||||
jump List.678 #Derived_gen.16 #Derived_gen.17 #Derived_gen.18 #Derived_gen.19 #Derived_gen.20;
|
||||
inc #Derived_gen.19;
|
||||
jump List.678 #Derived_gen.19 #Derived_gen.20 #Derived_gen.21 #Derived_gen.22 #Derived_gen.23;
|
||||
|
||||
procedure List.18 (List.172, List.173, List.174):
|
||||
let List.676 : U64 = 0i64;
|
||||
|
@ -105,32 +105,32 @@ procedure Num.96 (#Attr.2):
|
|||
ret Num.283;
|
||||
|
||||
procedure Str.12 (#Attr.2):
|
||||
let Str.256 : List U8 = lowlevel StrToUtf8 #Attr.2;
|
||||
ret Str.256;
|
||||
let Str.395 : List U8 = lowlevel StrToUtf8 #Attr.2;
|
||||
ret Str.395;
|
||||
|
||||
procedure Str.36 (#Attr.2):
|
||||
let Str.257 : U64 = lowlevel StrCountUtf8Bytes #Attr.2;
|
||||
ret Str.257;
|
||||
let Str.396 : U64 = lowlevel StrCountUtf8Bytes #Attr.2;
|
||||
ret Str.396;
|
||||
|
||||
procedure Str.43 (#Attr.2):
|
||||
let Str.254 : {U64, Str, Int1, U8} = lowlevel StrFromUtf8 #Attr.2;
|
||||
ret Str.254;
|
||||
let Str.393 : {U64, Str, Int1, U8} = lowlevel StrFromUtf8 #Attr.2;
|
||||
ret Str.393;
|
||||
|
||||
procedure Str.9 (Str.73):
|
||||
let Str.74 : {U64, Str, Int1, U8} = CallByName Str.43 Str.73;
|
||||
let Str.251 : Int1 = StructAtIndex 2 Str.74;
|
||||
if Str.251 then
|
||||
let Str.253 : Str = StructAtIndex 1 Str.74;
|
||||
let Str.252 : [C {U64, U8}, C Str] = TagId(1) Str.253;
|
||||
ret Str.252;
|
||||
procedure Str.9 (Str.79):
|
||||
let Str.80 : {U64, Str, Int1, U8} = CallByName Str.43 Str.79;
|
||||
let Str.390 : Int1 = StructAtIndex 2 Str.80;
|
||||
if Str.390 then
|
||||
let Str.392 : Str = StructAtIndex 1 Str.80;
|
||||
let Str.391 : [C {U64, U8}, C Str] = TagId(1) Str.392;
|
||||
ret Str.391;
|
||||
else
|
||||
let Str.249 : U64 = StructAtIndex 0 Str.74;
|
||||
let Str.250 : U8 = StructAtIndex 3 Str.74;
|
||||
let #Derived_gen.24 : Str = StructAtIndex 1 Str.74;
|
||||
let Str.388 : U64 = StructAtIndex 0 Str.80;
|
||||
let Str.389 : U8 = StructAtIndex 3 Str.80;
|
||||
let #Derived_gen.24 : Str = StructAtIndex 1 Str.80;
|
||||
dec #Derived_gen.24;
|
||||
let Str.248 : {U64, U8} = Struct {Str.249, Str.250};
|
||||
let Str.246 : [C {U64, U8}, C Str] = TagId(0) Str.248;
|
||||
ret Str.246;
|
||||
let Str.387 : {U64, U8} = Struct {Str.388, Str.389};
|
||||
let Str.385 : [C {U64, U8}, C Str] = TagId(0) Str.387;
|
||||
ret Str.385;
|
||||
|
||||
procedure Test.20 (Test.56):
|
||||
let Test.292 : Str = CallByName Encode.23 Test.56;
|
||||
|
|
|
@ -46,7 +46,7 @@ procedure Encode.26 (Encode.107, Encode.108):
|
|||
let Encode.110 : List U8 = CallByName Encode.24 Encode.111 Encode.112 Encode.108;
|
||||
ret Encode.110;
|
||||
|
||||
procedure List.101 (#Derived_gen.20, #Derived_gen.21, #Derived_gen.22, #Derived_gen.23, #Derived_gen.24):
|
||||
procedure List.101 (#Derived_gen.23, #Derived_gen.24, #Derived_gen.25, #Derived_gen.26, #Derived_gen.27):
|
||||
joinpoint List.678 List.175 List.176 List.177 List.178 List.179:
|
||||
let List.680 : Int1 = CallByName Num.22 List.178 List.179;
|
||||
if List.680 then
|
||||
|
@ -60,8 +60,8 @@ procedure List.101 (#Derived_gen.20, #Derived_gen.21, #Derived_gen.22, #Derived_
|
|||
dec List.175;
|
||||
ret List.176;
|
||||
in
|
||||
inc #Derived_gen.20;
|
||||
jump List.678 #Derived_gen.20 #Derived_gen.21 #Derived_gen.22 #Derived_gen.23 #Derived_gen.24;
|
||||
inc #Derived_gen.23;
|
||||
jump List.678 #Derived_gen.23 #Derived_gen.24 #Derived_gen.25 #Derived_gen.26 #Derived_gen.27;
|
||||
|
||||
procedure List.18 (List.172, List.173, List.174):
|
||||
let List.676 : U64 = 0i64;
|
||||
|
@ -112,32 +112,32 @@ procedure Num.96 (#Attr.2):
|
|||
ret Num.283;
|
||||
|
||||
procedure Str.12 (#Attr.2):
|
||||
let Str.256 : List U8 = lowlevel StrToUtf8 #Attr.2;
|
||||
ret Str.256;
|
||||
let Str.395 : List U8 = lowlevel StrToUtf8 #Attr.2;
|
||||
ret Str.395;
|
||||
|
||||
procedure Str.36 (#Attr.2):
|
||||
let Str.257 : U64 = lowlevel StrCountUtf8Bytes #Attr.2;
|
||||
ret Str.257;
|
||||
let Str.396 : U64 = lowlevel StrCountUtf8Bytes #Attr.2;
|
||||
ret Str.396;
|
||||
|
||||
procedure Str.43 (#Attr.2):
|
||||
let Str.254 : {U64, Str, Int1, U8} = lowlevel StrFromUtf8 #Attr.2;
|
||||
ret Str.254;
|
||||
let Str.393 : {U64, Str, Int1, U8} = lowlevel StrFromUtf8 #Attr.2;
|
||||
ret Str.393;
|
||||
|
||||
procedure Str.9 (Str.73):
|
||||
let Str.74 : {U64, Str, Int1, U8} = CallByName Str.43 Str.73;
|
||||
let Str.251 : Int1 = StructAtIndex 2 Str.74;
|
||||
if Str.251 then
|
||||
let Str.253 : Str = StructAtIndex 1 Str.74;
|
||||
let Str.252 : [C {U64, U8}, C Str] = TagId(1) Str.253;
|
||||
ret Str.252;
|
||||
procedure Str.9 (Str.79):
|
||||
let Str.80 : {U64, Str, Int1, U8} = CallByName Str.43 Str.79;
|
||||
let Str.390 : Int1 = StructAtIndex 2 Str.80;
|
||||
if Str.390 then
|
||||
let Str.392 : Str = StructAtIndex 1 Str.80;
|
||||
let Str.391 : [C {U64, U8}, C Str] = TagId(1) Str.392;
|
||||
ret Str.391;
|
||||
else
|
||||
let Str.249 : U64 = StructAtIndex 0 Str.74;
|
||||
let Str.250 : U8 = StructAtIndex 3 Str.74;
|
||||
let #Derived_gen.28 : Str = StructAtIndex 1 Str.74;
|
||||
let Str.388 : U64 = StructAtIndex 0 Str.80;
|
||||
let Str.389 : U8 = StructAtIndex 3 Str.80;
|
||||
let #Derived_gen.28 : Str = StructAtIndex 1 Str.80;
|
||||
dec #Derived_gen.28;
|
||||
let Str.248 : {U64, U8} = Struct {Str.249, Str.250};
|
||||
let Str.246 : [C {U64, U8}, C Str] = TagId(0) Str.248;
|
||||
ret Str.246;
|
||||
let Str.387 : {U64, U8} = Struct {Str.388, Str.389};
|
||||
let Str.385 : [C {U64, U8}, C Str] = TagId(0) Str.387;
|
||||
ret Str.385;
|
||||
|
||||
procedure Test.20 (Test.56):
|
||||
let Test.296 : Str = CallByName Encode.23 Test.56;
|
||||
|
|
|
@ -38,32 +38,32 @@ procedure Num.96 (#Attr.2):
|
|||
ret Num.283;
|
||||
|
||||
procedure Str.12 (#Attr.2):
|
||||
let Str.256 : List U8 = lowlevel StrToUtf8 #Attr.2;
|
||||
ret Str.256;
|
||||
let Str.395 : List U8 = lowlevel StrToUtf8 #Attr.2;
|
||||
ret Str.395;
|
||||
|
||||
procedure Str.36 (#Attr.2):
|
||||
let Str.257 : U64 = lowlevel StrCountUtf8Bytes #Attr.2;
|
||||
ret Str.257;
|
||||
let Str.396 : U64 = lowlevel StrCountUtf8Bytes #Attr.2;
|
||||
ret Str.396;
|
||||
|
||||
procedure Str.43 (#Attr.2):
|
||||
let Str.254 : {U64, Str, Int1, U8} = lowlevel StrFromUtf8 #Attr.2;
|
||||
ret Str.254;
|
||||
let Str.393 : {U64, Str, Int1, U8} = lowlevel StrFromUtf8 #Attr.2;
|
||||
ret Str.393;
|
||||
|
||||
procedure Str.9 (Str.73):
|
||||
let Str.74 : {U64, Str, Int1, U8} = CallByName Str.43 Str.73;
|
||||
let Str.251 : Int1 = StructAtIndex 2 Str.74;
|
||||
if Str.251 then
|
||||
let Str.253 : Str = StructAtIndex 1 Str.74;
|
||||
let Str.252 : [C {U64, U8}, C Str] = TagId(1) Str.253;
|
||||
ret Str.252;
|
||||
procedure Str.9 (Str.79):
|
||||
let Str.80 : {U64, Str, Int1, U8} = CallByName Str.43 Str.79;
|
||||
let Str.390 : Int1 = StructAtIndex 2 Str.80;
|
||||
if Str.390 then
|
||||
let Str.392 : Str = StructAtIndex 1 Str.80;
|
||||
let Str.391 : [C {U64, U8}, C Str] = TagId(1) Str.392;
|
||||
ret Str.391;
|
||||
else
|
||||
let Str.249 : U64 = StructAtIndex 0 Str.74;
|
||||
let Str.250 : U8 = StructAtIndex 3 Str.74;
|
||||
let #Derived_gen.3 : Str = StructAtIndex 1 Str.74;
|
||||
let Str.388 : U64 = StructAtIndex 0 Str.80;
|
||||
let Str.389 : U8 = StructAtIndex 3 Str.80;
|
||||
let #Derived_gen.3 : Str = StructAtIndex 1 Str.80;
|
||||
dec #Derived_gen.3;
|
||||
let Str.248 : {U64, U8} = Struct {Str.249, Str.250};
|
||||
let Str.246 : [C {U64, U8}, C Str] = TagId(0) Str.248;
|
||||
ret Str.246;
|
||||
let Str.387 : {U64, U8} = Struct {Str.388, Str.389};
|
||||
let Str.385 : [C {U64, U8}, C Str] = TagId(0) Str.387;
|
||||
ret Str.385;
|
||||
|
||||
procedure Test.20 (Test.56):
|
||||
let Test.259 : Str = CallByName Encode.23 Test.56;
|
||||
|
|
|
@ -40,7 +40,7 @@ procedure Encode.26 (Encode.107, Encode.108):
|
|||
let Encode.110 : List U8 = CallByName Encode.24 Encode.111 Encode.112 Encode.108;
|
||||
ret Encode.110;
|
||||
|
||||
procedure List.101 (#Derived_gen.10, #Derived_gen.11, #Derived_gen.12, #Derived_gen.13, #Derived_gen.14):
|
||||
procedure List.101 (#Derived_gen.22, #Derived_gen.23, #Derived_gen.24, #Derived_gen.25, #Derived_gen.26):
|
||||
joinpoint List.678 List.175 List.176 List.177 List.178 List.179:
|
||||
let List.680 : Int1 = CallByName Num.22 List.178 List.179;
|
||||
if List.680 then
|
||||
|
@ -54,8 +54,8 @@ procedure List.101 (#Derived_gen.10, #Derived_gen.11, #Derived_gen.12, #Derived_
|
|||
dec List.175;
|
||||
ret List.176;
|
||||
in
|
||||
inc #Derived_gen.10;
|
||||
jump List.678 #Derived_gen.10 #Derived_gen.11 #Derived_gen.12 #Derived_gen.13 #Derived_gen.14;
|
||||
inc #Derived_gen.22;
|
||||
jump List.678 #Derived_gen.22 #Derived_gen.23 #Derived_gen.24 #Derived_gen.25 #Derived_gen.26;
|
||||
|
||||
procedure List.13 (#Attr.2, #Attr.3):
|
||||
let List.701 : List Str = lowlevel ListPrepend #Attr.2 #Attr.3;
|
||||
|
@ -110,32 +110,32 @@ procedure Num.96 (#Attr.2):
|
|||
ret Num.283;
|
||||
|
||||
procedure Str.12 (#Attr.2):
|
||||
let Str.256 : List U8 = lowlevel StrToUtf8 #Attr.2;
|
||||
ret Str.256;
|
||||
let Str.395 : List U8 = lowlevel StrToUtf8 #Attr.2;
|
||||
ret Str.395;
|
||||
|
||||
procedure Str.36 (#Attr.2):
|
||||
let Str.257 : U64 = lowlevel StrCountUtf8Bytes #Attr.2;
|
||||
ret Str.257;
|
||||
let Str.396 : U64 = lowlevel StrCountUtf8Bytes #Attr.2;
|
||||
ret Str.396;
|
||||
|
||||
procedure Str.43 (#Attr.2):
|
||||
let Str.254 : {U64, Str, Int1, U8} = lowlevel StrFromUtf8 #Attr.2;
|
||||
ret Str.254;
|
||||
let Str.393 : {U64, Str, Int1, U8} = lowlevel StrFromUtf8 #Attr.2;
|
||||
ret Str.393;
|
||||
|
||||
procedure Str.9 (Str.73):
|
||||
let Str.74 : {U64, Str, Int1, U8} = CallByName Str.43 Str.73;
|
||||
let Str.251 : Int1 = StructAtIndex 2 Str.74;
|
||||
if Str.251 then
|
||||
let Str.253 : Str = StructAtIndex 1 Str.74;
|
||||
let Str.252 : [C {U64, U8}, C Str] = TagId(1) Str.253;
|
||||
ret Str.252;
|
||||
procedure Str.9 (Str.79):
|
||||
let Str.80 : {U64, Str, Int1, U8} = CallByName Str.43 Str.79;
|
||||
let Str.390 : Int1 = StructAtIndex 2 Str.80;
|
||||
if Str.390 then
|
||||
let Str.392 : Str = StructAtIndex 1 Str.80;
|
||||
let Str.391 : [C {U64, U8}, C Str] = TagId(1) Str.392;
|
||||
ret Str.391;
|
||||
else
|
||||
let Str.249 : U64 = StructAtIndex 0 Str.74;
|
||||
let Str.250 : U8 = StructAtIndex 3 Str.74;
|
||||
let #Derived_gen.27 : Str = StructAtIndex 1 Str.74;
|
||||
let Str.388 : U64 = StructAtIndex 0 Str.80;
|
||||
let Str.389 : U8 = StructAtIndex 3 Str.80;
|
||||
let #Derived_gen.27 : Str = StructAtIndex 1 Str.80;
|
||||
dec #Derived_gen.27;
|
||||
let Str.248 : {U64, U8} = Struct {Str.249, Str.250};
|
||||
let Str.246 : [C {U64, U8}, C Str] = TagId(0) Str.248;
|
||||
ret Str.246;
|
||||
let Str.387 : {U64, U8} = Struct {Str.388, Str.389};
|
||||
let Str.385 : [C {U64, U8}, C Str] = TagId(0) Str.387;
|
||||
ret Str.385;
|
||||
|
||||
procedure Test.20 (Test.56):
|
||||
let Test.297 : Str = CallByName Encode.23 Test.56;
|
||||
|
|
|
@ -43,7 +43,7 @@ procedure Encode.26 (Encode.107, Encode.108):
|
|||
let Encode.110 : List U8 = CallByName Encode.24 Encode.111 Encode.112 Encode.108;
|
||||
ret Encode.110;
|
||||
|
||||
procedure List.101 (#Derived_gen.20, #Derived_gen.21, #Derived_gen.22, #Derived_gen.23, #Derived_gen.24):
|
||||
procedure List.101 (#Derived_gen.23, #Derived_gen.24, #Derived_gen.25, #Derived_gen.26, #Derived_gen.27):
|
||||
joinpoint List.678 List.175 List.176 List.177 List.178 List.179:
|
||||
let List.680 : Int1 = CallByName Num.22 List.178 List.179;
|
||||
if List.680 then
|
||||
|
@ -57,8 +57,8 @@ procedure List.101 (#Derived_gen.20, #Derived_gen.21, #Derived_gen.22, #Derived_
|
|||
dec List.175;
|
||||
ret List.176;
|
||||
in
|
||||
inc #Derived_gen.20;
|
||||
jump List.678 #Derived_gen.20 #Derived_gen.21 #Derived_gen.22 #Derived_gen.23 #Derived_gen.24;
|
||||
inc #Derived_gen.23;
|
||||
jump List.678 #Derived_gen.23 #Derived_gen.24 #Derived_gen.25 #Derived_gen.26 #Derived_gen.27;
|
||||
|
||||
procedure List.13 (#Attr.2, #Attr.3):
|
||||
let List.701 : List Str = lowlevel ListPrepend #Attr.2 #Attr.3;
|
||||
|
@ -113,32 +113,32 @@ procedure Num.96 (#Attr.2):
|
|||
ret Num.283;
|
||||
|
||||
procedure Str.12 (#Attr.2):
|
||||
let Str.256 : List U8 = lowlevel StrToUtf8 #Attr.2;
|
||||
ret Str.256;
|
||||
let Str.395 : List U8 = lowlevel StrToUtf8 #Attr.2;
|
||||
ret Str.395;
|
||||
|
||||
procedure Str.36 (#Attr.2):
|
||||
let Str.257 : U64 = lowlevel StrCountUtf8Bytes #Attr.2;
|
||||
ret Str.257;
|
||||
let Str.396 : U64 = lowlevel StrCountUtf8Bytes #Attr.2;
|
||||
ret Str.396;
|
||||
|
||||
procedure Str.43 (#Attr.2):
|
||||
let Str.254 : {U64, Str, Int1, U8} = lowlevel StrFromUtf8 #Attr.2;
|
||||
ret Str.254;
|
||||
let Str.393 : {U64, Str, Int1, U8} = lowlevel StrFromUtf8 #Attr.2;
|
||||
ret Str.393;
|
||||
|
||||
procedure Str.9 (Str.73):
|
||||
let Str.74 : {U64, Str, Int1, U8} = CallByName Str.43 Str.73;
|
||||
let Str.251 : Int1 = StructAtIndex 2 Str.74;
|
||||
if Str.251 then
|
||||
let Str.253 : Str = StructAtIndex 1 Str.74;
|
||||
let Str.252 : [C {U64, U8}, C Str] = TagId(1) Str.253;
|
||||
ret Str.252;
|
||||
procedure Str.9 (Str.79):
|
||||
let Str.80 : {U64, Str, Int1, U8} = CallByName Str.43 Str.79;
|
||||
let Str.390 : Int1 = StructAtIndex 2 Str.80;
|
||||
if Str.390 then
|
||||
let Str.392 : Str = StructAtIndex 1 Str.80;
|
||||
let Str.391 : [C {U64, U8}, C Str] = TagId(1) Str.392;
|
||||
ret Str.391;
|
||||
else
|
||||
let Str.249 : U64 = StructAtIndex 0 Str.74;
|
||||
let Str.250 : U8 = StructAtIndex 3 Str.74;
|
||||
let #Derived_gen.28 : Str = StructAtIndex 1 Str.74;
|
||||
let Str.388 : U64 = StructAtIndex 0 Str.80;
|
||||
let Str.389 : U8 = StructAtIndex 3 Str.80;
|
||||
let #Derived_gen.28 : Str = StructAtIndex 1 Str.80;
|
||||
dec #Derived_gen.28;
|
||||
let Str.248 : {U64, U8} = Struct {Str.249, Str.250};
|
||||
let Str.246 : [C {U64, U8}, C Str] = TagId(0) Str.248;
|
||||
ret Str.246;
|
||||
let Str.387 : {U64, U8} = Struct {Str.388, Str.389};
|
||||
let Str.385 : [C {U64, U8}, C Str] = TagId(0) Str.387;
|
||||
ret Str.385;
|
||||
|
||||
procedure Test.20 (Test.56):
|
||||
let Test.301 : Str = CallByName Encode.23 Test.56;
|
||||
|
|
|
@ -6,7 +6,7 @@ procedure Num.21 (#Attr.2, #Attr.3):
|
|||
let Num.283 : I64 = lowlevel NumMul #Attr.2 #Attr.3;
|
||||
ret Num.283;
|
||||
|
||||
procedure Test.1 (#Derived_gen.0, #Derived_gen.1):
|
||||
procedure Test.1 (Bool.21, Bool.22):
|
||||
joinpoint Test.7 Test.2 Test.3:
|
||||
let Test.13 : I64 = 0i64;
|
||||
let Test.14 : Int1 = lowlevel Eq Test.13 Test.2;
|
||||
|
@ -18,7 +18,7 @@ procedure Test.1 (#Derived_gen.0, #Derived_gen.1):
|
|||
let Test.11 : I64 = CallByName Num.21 Test.2 Test.3;
|
||||
jump Test.7 Test.10 Test.11;
|
||||
in
|
||||
jump Test.7 #Derived_gen.0 #Derived_gen.1;
|
||||
jump Test.7 Bool.21 Bool.22;
|
||||
|
||||
procedure Test.0 ():
|
||||
let Test.5 : I64 = 10i64;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
procedure Bool.1 ():
|
||||
let Bool.23 : Int1 = false;
|
||||
ret Bool.23;
|
||||
let Bool.21 : Int1 = false;
|
||||
ret Bool.21;
|
||||
|
||||
procedure Test.1 (Test.2):
|
||||
let Test.5 : I64 = 2i64;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
procedure Bool.11 (#Attr.2, #Attr.3):
|
||||
let Bool.23 : Int1 = lowlevel Eq #Attr.2 #Attr.3;
|
||||
ret Bool.23;
|
||||
procedure Bool.9 (#Attr.2, #Attr.3):
|
||||
let Bool.21 : Int1 = lowlevel Eq #Attr.2 #Attr.3;
|
||||
ret Bool.21;
|
||||
|
||||
procedure Test.1 (Test.3):
|
||||
let Test.6 : I64 = 10i64;
|
||||
|
@ -13,7 +13,7 @@ procedure Test.1 (Test.3):
|
|||
ret Test.8;
|
||||
in
|
||||
let Test.12 : I64 = 5i64;
|
||||
let Test.11 : Int1 = CallByName Bool.11 Test.6 Test.12;
|
||||
let Test.11 : Int1 = CallByName Bool.9 Test.6 Test.12;
|
||||
jump Test.10 Test.11;
|
||||
|
||||
procedure Test.0 ():
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
procedure Bool.1 ():
|
||||
let Bool.23 : Int1 = false;
|
||||
ret Bool.23;
|
||||
let Bool.21 : Int1 = false;
|
||||
ret Bool.21;
|
||||
|
||||
procedure Bool.2 ():
|
||||
let Bool.24 : Int1 = true;
|
||||
ret Bool.24;
|
||||
let Bool.22 : Int1 = true;
|
||||
ret Bool.22;
|
||||
|
||||
procedure Test.0 ():
|
||||
let Test.4 : Int1 = CallByName Bool.2;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
procedure Bool.1 ():
|
||||
let Bool.23 : Int1 = false;
|
||||
ret Bool.23;
|
||||
let Bool.21 : Int1 = false;
|
||||
ret Bool.21;
|
||||
|
||||
procedure Num.19 (#Attr.2, #Attr.3):
|
||||
let Num.283 : I64 = lowlevel NumAdd #Attr.2 #Attr.3;
|
||||
|
@ -9,7 +9,7 @@ procedure Num.19 (#Attr.2, #Attr.3):
|
|||
procedure Test.3 (Test.4):
|
||||
ret Test.4;
|
||||
|
||||
procedure Test.0 (#Derived_gen.0):
|
||||
procedure Test.0 (Bool.22):
|
||||
joinpoint Test.5 Test.1:
|
||||
joinpoint Test.10 Test.2:
|
||||
let Test.8 : I64 = 1i64;
|
||||
|
@ -31,4 +31,4 @@ procedure Test.0 (#Derived_gen.0):
|
|||
let Test.9 : Int1 = true;
|
||||
jump Test.10 Test.9;
|
||||
in
|
||||
jump Test.5 #Derived_gen.0;
|
||||
jump Test.5 Bool.22;
|
||||
|
|
|
@ -34,7 +34,7 @@ procedure Test.8 (Test.9):
|
|||
let Test.23 : I64 = CallByName Num.19 Test.9 Test.24;
|
||||
ret Test.23;
|
||||
|
||||
procedure Test.0 (#Derived_gen.0):
|
||||
procedure Test.0 (Bool.21):
|
||||
joinpoint Test.11 Test.1:
|
||||
let Test.25 : I64 = 1i64;
|
||||
let Test.13 : I64 = CallByName Num.19 Test.1 Test.25;
|
||||
|
@ -57,4 +57,4 @@ procedure Test.0 (#Derived_gen.0):
|
|||
ret Test.12;
|
||||
|
||||
in
|
||||
jump Test.11 #Derived_gen.0;
|
||||
jump Test.11 Bool.21;
|
||||
|
|
|
@ -17,7 +17,7 @@ procedure Test.4 (Test.5, #Attr.12):
|
|||
let Test.16 : I64 = CallByName Num.19 Test.5 Test.17;
|
||||
ret Test.16;
|
||||
|
||||
procedure Test.0 (#Derived_gen.0):
|
||||
procedure Test.0 (Bool.21):
|
||||
joinpoint Test.7 Test.1:
|
||||
let Test.21 : I64 = 1i64;
|
||||
let Test.9 : I64 = CallByName Num.19 Test.1 Test.21;
|
||||
|
@ -33,4 +33,4 @@ procedure Test.0 (#Derived_gen.0):
|
|||
ret Test.8;
|
||||
|
||||
in
|
||||
jump Test.7 #Derived_gen.0;
|
||||
jump Test.7 Bool.21;
|
||||
|
|
1045
crates/compiler/test_mono/generated/inspect_derived_dict.txt
generated
1045
crates/compiler/test_mono/generated/inspect_derived_dict.txt
generated
File diff suppressed because it is too large
Load diff
|
@ -14,12 +14,12 @@ procedure #Derived.4 (#Derived.5, #Derived.1):
|
|||
ret #Derived_gen.3;
|
||||
|
||||
procedure Bool.1 ():
|
||||
let Bool.24 : Int1 = false;
|
||||
ret Bool.24;
|
||||
let Bool.22 : Int1 = false;
|
||||
ret Bool.22;
|
||||
|
||||
procedure Bool.2 ():
|
||||
let Bool.23 : Int1 = true;
|
||||
ret Bool.23;
|
||||
let Bool.21 : Int1 = true;
|
||||
ret Bool.21;
|
||||
|
||||
procedure Inspect.156 (Inspect.157, #Attr.12):
|
||||
let Inspect.155 : {} = StructAtIndex 2 #Attr.12;
|
||||
|
@ -120,7 +120,7 @@ procedure Inspect.63 (Inspect.295, Inspect.291):
|
|||
procedure Inspect.64 (Inspect.297):
|
||||
ret Inspect.297;
|
||||
|
||||
procedure List.101 (#Derived_gen.11, #Derived_gen.12, #Derived_gen.13, #Derived_gen.14, #Derived_gen.15):
|
||||
procedure List.101 (#Derived_gen.10, #Derived_gen.11, #Derived_gen.12, #Derived_gen.13, #Derived_gen.14):
|
||||
joinpoint List.678 List.175 List.176 List.177 List.178 List.179:
|
||||
let List.680 : Int1 = CallByName Num.22 List.178 List.179;
|
||||
if List.680 then
|
||||
|
@ -133,8 +133,8 @@ procedure List.101 (#Derived_gen.11, #Derived_gen.12, #Derived_gen.13, #Derived_
|
|||
dec List.175;
|
||||
ret List.176;
|
||||
in
|
||||
inc #Derived_gen.11;
|
||||
jump List.678 #Derived_gen.11 #Derived_gen.12 #Derived_gen.13 #Derived_gen.14 #Derived_gen.15;
|
||||
inc #Derived_gen.10;
|
||||
jump List.678 #Derived_gen.10 #Derived_gen.11 #Derived_gen.12 #Derived_gen.13 #Derived_gen.14;
|
||||
|
||||
procedure List.18 (List.172, List.173, List.174):
|
||||
let List.676 : U64 = 0i64;
|
||||
|
@ -163,8 +163,8 @@ procedure Num.96 (#Attr.2):
|
|||
ret Num.283;
|
||||
|
||||
procedure Str.3 (#Attr.2, #Attr.3):
|
||||
let Str.246 : Str = lowlevel StrConcat #Attr.2 #Attr.3;
|
||||
ret Str.246;
|
||||
let Str.385 : Str = lowlevel StrConcat #Attr.2 #Attr.3;
|
||||
ret Str.385;
|
||||
|
||||
procedure Test.0 ():
|
||||
let Test.2 : List I64 = Array [1i64, 2i64, 3i64];
|
||||
|
|
|
@ -27,23 +27,19 @@ procedure #Derived.6 (#Derived.7, #Derived.5):
|
|||
ret #Derived_gen.13;
|
||||
|
||||
procedure Bool.1 ():
|
||||
let Bool.26 : Int1 = false;
|
||||
ret Bool.26;
|
||||
|
||||
procedure Bool.11 (#Attr.2, #Attr.3):
|
||||
let Bool.28 : Int1 = lowlevel Eq #Attr.2 #Attr.3;
|
||||
ret Bool.28;
|
||||
|
||||
procedure Bool.11 (#Attr.2, #Attr.3):
|
||||
let Bool.29 : Int1 = lowlevel Eq #Attr.2 #Attr.3;
|
||||
ret Bool.29;
|
||||
|
||||
procedure Bool.2 ():
|
||||
let Bool.25 : Int1 = true;
|
||||
let Bool.25 : Int1 = false;
|
||||
ret Bool.25;
|
||||
|
||||
procedure Bool.3 (#Attr.2, #Attr.3):
|
||||
let Bool.27 : Int1 = lowlevel And #Attr.2 #Attr.3;
|
||||
procedure Bool.2 ():
|
||||
let Bool.23 : Int1 = true;
|
||||
ret Bool.23;
|
||||
|
||||
procedure Bool.9 (#Attr.2, #Attr.3):
|
||||
let Bool.26 : Int1 = lowlevel Eq #Attr.2 #Attr.3;
|
||||
ret Bool.26;
|
||||
|
||||
procedure Bool.9 (#Attr.2, #Attr.3):
|
||||
let Bool.27 : Int1 = lowlevel Eq #Attr.2 #Attr.3;
|
||||
ret Bool.27;
|
||||
|
||||
procedure Inspect.225 (Inspect.226, Inspect.224):
|
||||
|
@ -235,7 +231,7 @@ procedure Inspect.63 (Inspect.295, Inspect.291):
|
|||
procedure Inspect.64 (Inspect.297):
|
||||
ret Inspect.297;
|
||||
|
||||
procedure List.101 (#Derived_gen.20, #Derived_gen.21, #Derived_gen.22, #Derived_gen.23, #Derived_gen.24):
|
||||
procedure List.101 (#Derived_gen.33, #Derived_gen.34, #Derived_gen.35, #Derived_gen.36, #Derived_gen.37):
|
||||
joinpoint List.678 List.175 List.176 List.177 List.178 List.179:
|
||||
let List.680 : Int1 = CallByName Num.22 List.178 List.179;
|
||||
if List.680 then
|
||||
|
@ -249,10 +245,10 @@ procedure List.101 (#Derived_gen.20, #Derived_gen.21, #Derived_gen.22, #Derived_
|
|||
dec List.175;
|
||||
ret List.176;
|
||||
in
|
||||
inc #Derived_gen.20;
|
||||
jump List.678 #Derived_gen.20 #Derived_gen.21 #Derived_gen.22 #Derived_gen.23 #Derived_gen.24;
|
||||
inc #Derived_gen.33;
|
||||
jump List.678 #Derived_gen.33 #Derived_gen.34 #Derived_gen.35 #Derived_gen.36 #Derived_gen.37;
|
||||
|
||||
procedure List.101 (#Derived_gen.39, #Derived_gen.40, #Derived_gen.41, #Derived_gen.42, #Derived_gen.43):
|
||||
procedure List.101 (#Derived_gen.38, #Derived_gen.39, #Derived_gen.40, #Derived_gen.41, #Derived_gen.42):
|
||||
joinpoint List.690 List.175 List.176 List.177 List.178 List.179:
|
||||
let List.692 : Int1 = CallByName Num.22 List.178 List.179;
|
||||
if List.692 then
|
||||
|
@ -266,8 +262,8 @@ procedure List.101 (#Derived_gen.39, #Derived_gen.40, #Derived_gen.41, #Derived_
|
|||
dec List.175;
|
||||
ret List.176;
|
||||
in
|
||||
inc #Derived_gen.39;
|
||||
jump List.690 #Derived_gen.39 #Derived_gen.40 #Derived_gen.41 #Derived_gen.42 #Derived_gen.43;
|
||||
inc #Derived_gen.38;
|
||||
jump List.690 #Derived_gen.38 #Derived_gen.39 #Derived_gen.40 #Derived_gen.41 #Derived_gen.42;
|
||||
|
||||
procedure List.18 (List.172, List.173, List.174):
|
||||
let List.676 : U64 = 0i64;
|
||||
|
@ -326,181 +322,184 @@ procedure Num.77 (#Attr.2, #Attr.3):
|
|||
ret Num.295;
|
||||
|
||||
procedure Str.20 (#Attr.2):
|
||||
let Str.314 : Str = lowlevel StrWithCapacity #Attr.2;
|
||||
ret Str.314;
|
||||
let Str.454 : Str = lowlevel StrWithCapacity #Attr.2;
|
||||
ret Str.454;
|
||||
|
||||
procedure Str.3 (#Attr.2, #Attr.3):
|
||||
let Str.247 : Str = lowlevel StrConcat #Attr.2 #Attr.3;
|
||||
ret Str.247;
|
||||
let Str.386 : Str = lowlevel StrConcat #Attr.2 #Attr.3;
|
||||
ret Str.386;
|
||||
|
||||
procedure Str.35 (#Attr.2, #Attr.3):
|
||||
let Str.304 : U8 = lowlevel StrGetUnsafe #Attr.2 #Attr.3;
|
||||
ret Str.304;
|
||||
let Str.444 : U8 = lowlevel StrGetUnsafe #Attr.2 #Attr.3;
|
||||
ret Str.444;
|
||||
|
||||
procedure Str.36 (#Attr.2):
|
||||
let Str.267 : U64 = lowlevel StrCountUtf8Bytes #Attr.2;
|
||||
ret Str.267;
|
||||
let Str.406 : U64 = lowlevel StrCountUtf8Bytes #Attr.2;
|
||||
ret Str.406;
|
||||
|
||||
procedure Str.37 (#Attr.2, #Attr.3, #Attr.4):
|
||||
let Str.265 : Str = lowlevel StrSubstringUnsafe #Attr.2 #Attr.3 #Attr.4;
|
||||
ret Str.265;
|
||||
let Str.404 : Str = lowlevel StrSubstringUnsafe #Attr.2 #Attr.3 #Attr.4;
|
||||
ret Str.404;
|
||||
|
||||
procedure Str.38 (Str.112, Str.113):
|
||||
let Str.261 : [C , C U64] = CallByName Str.57 Str.112 Str.113;
|
||||
let Str.274 : U8 = 1i64;
|
||||
let Str.275 : U8 = GetTagId Str.261;
|
||||
let Str.276 : Int1 = lowlevel Eq Str.274 Str.275;
|
||||
if Str.276 then
|
||||
let Str.114 : U64 = UnionAtIndex (Id 1) (Index 0) Str.261;
|
||||
let Str.270 : U64 = CallByName Str.36 Str.112;
|
||||
let Str.271 : U64 = CallByName Str.36 Str.113;
|
||||
let Str.269 : U64 = CallByName Num.20 Str.270 Str.271;
|
||||
let Str.115 : U64 = CallByName Num.20 Str.269 Str.114;
|
||||
let Str.268 : U64 = 0i64;
|
||||
inc Str.112;
|
||||
let Str.116 : Str = CallByName Str.37 Str.112 Str.268 Str.114;
|
||||
let Str.266 : U64 = CallByName Str.36 Str.113;
|
||||
let Str.264 : U64 = CallByName Num.51 Str.114 Str.266;
|
||||
let Str.117 : Str = CallByName Str.37 Str.112 Str.264 Str.115;
|
||||
let Str.263 : {Str, Str} = Struct {Str.117, Str.116};
|
||||
let Str.262 : [C {}, C {Str, Str}] = TagId(1) Str.263;
|
||||
ret Str.262;
|
||||
procedure Str.38 (Str.213, Str.214):
|
||||
let Str.400 : [C , C U64] = CallByName Str.65 Str.213 Str.214;
|
||||
let Str.413 : U8 = 1i64;
|
||||
let Str.414 : U8 = GetTagId Str.400;
|
||||
let Str.415 : Int1 = lowlevel Eq Str.413 Str.414;
|
||||
if Str.415 then
|
||||
let Str.215 : U64 = UnionAtIndex (Id 1) (Index 0) Str.400;
|
||||
let Str.409 : U64 = CallByName Str.36 Str.213;
|
||||
let Str.410 : U64 = CallByName Str.36 Str.214;
|
||||
let Str.408 : U64 = CallByName Num.20 Str.409 Str.410;
|
||||
let Str.216 : U64 = CallByName Num.20 Str.408 Str.215;
|
||||
let Str.407 : U64 = 0i64;
|
||||
inc Str.213;
|
||||
let Str.217 : Str = CallByName Str.37 Str.213 Str.407 Str.215;
|
||||
let Str.405 : U64 = CallByName Str.36 Str.214;
|
||||
let Str.403 : U64 = CallByName Num.51 Str.215 Str.405;
|
||||
let Str.218 : Str = CallByName Str.37 Str.213 Str.403 Str.216;
|
||||
let Str.402 : {Str, Str} = Struct {Str.218, Str.217};
|
||||
let Str.401 : [C {}, C {Str, Str}] = TagId(1) Str.402;
|
||||
ret Str.401;
|
||||
else
|
||||
dec Str.112;
|
||||
let Str.273 : {} = Struct {};
|
||||
let Str.272 : [C {}, C {Str, Str}] = TagId(0) Str.273;
|
||||
ret Str.272;
|
||||
dec Str.213;
|
||||
let Str.412 : {} = Struct {};
|
||||
let Str.411 : [C {}, C {Str, Str}] = TagId(0) Str.412;
|
||||
ret Str.411;
|
||||
|
||||
procedure Str.45 (Str.91, Str.92, Str.93):
|
||||
inc Str.91;
|
||||
let Str.342 : [C {}, C {Str, Str}] = CallByName Str.38 Str.91 Str.92;
|
||||
let Str.350 : U8 = 1i64;
|
||||
let Str.351 : U8 = GetTagId Str.342;
|
||||
let Str.352 : Int1 = lowlevel Eq Str.350 Str.351;
|
||||
if Str.352 then
|
||||
let Str.349 : {Str, Str} = UnionAtIndex (Id 1) (Index 0) Str.342;
|
||||
let Str.95 : Str = StructAtIndex 0 Str.349;
|
||||
let Str.94 : Str = StructAtIndex 1 Str.349;
|
||||
let Str.347 : U64 = CallByName Str.36 Str.91;
|
||||
dec Str.91;
|
||||
let Str.346 : Str = CallByName Str.20 Str.347;
|
||||
let Str.345 : Str = CallByName Str.3 Str.346 Str.94;
|
||||
dec Str.94;
|
||||
let Str.344 : Str = CallByName Str.3 Str.345 Str.93;
|
||||
let Str.343 : Str = CallByName Str.56 Str.344 Str.95 Str.92 Str.93;
|
||||
ret Str.343;
|
||||
procedure Str.45 (Str.192, Str.193, Str.194):
|
||||
inc Str.192;
|
||||
let Str.482 : [C {}, C {Str, Str}] = CallByName Str.38 Str.192 Str.193;
|
||||
let Str.490 : U8 = 1i64;
|
||||
let Str.491 : U8 = GetTagId Str.482;
|
||||
let Str.492 : Int1 = lowlevel Eq Str.490 Str.491;
|
||||
if Str.492 then
|
||||
let Str.489 : {Str, Str} = UnionAtIndex (Id 1) (Index 0) Str.482;
|
||||
let Str.196 : Str = StructAtIndex 0 Str.489;
|
||||
let Str.195 : Str = StructAtIndex 1 Str.489;
|
||||
let Str.487 : U64 = CallByName Str.36 Str.192;
|
||||
dec Str.192;
|
||||
let Str.486 : Str = CallByName Str.20 Str.487;
|
||||
let Str.485 : Str = CallByName Str.3 Str.486 Str.195;
|
||||
dec Str.195;
|
||||
let Str.484 : Str = CallByName Str.3 Str.485 Str.194;
|
||||
let Str.483 : Str = CallByName Str.64 Str.484 Str.196 Str.193 Str.194;
|
||||
ret Str.483;
|
||||
else
|
||||
dec Str.342;
|
||||
ret Str.91;
|
||||
dec Str.482;
|
||||
ret Str.192;
|
||||
|
||||
procedure Str.56 (#Derived_gen.27, #Derived_gen.28, #Derived_gen.29, #Derived_gen.30):
|
||||
joinpoint Str.251 Str.96 Str.97 Str.98 Str.99:
|
||||
inc Str.97;
|
||||
let Str.252 : [C {}, C {Str, Str}] = CallByName Str.38 Str.97 Str.98;
|
||||
let Str.258 : U8 = 1i64;
|
||||
let Str.259 : U8 = GetTagId Str.252;
|
||||
let Str.260 : Int1 = lowlevel Eq Str.258 Str.259;
|
||||
if Str.260 then
|
||||
dec Str.97;
|
||||
let Str.257 : {Str, Str} = UnionAtIndex (Id 1) (Index 0) Str.252;
|
||||
let Str.101 : Str = StructAtIndex 0 Str.257;
|
||||
let Str.100 : Str = StructAtIndex 1 Str.257;
|
||||
let Str.255 : Str = CallByName Str.3 Str.96 Str.100;
|
||||
dec Str.100;
|
||||
let Str.254 : Str = CallByName Str.3 Str.255 Str.99;
|
||||
jump Str.251 Str.254 Str.101 Str.98 Str.99;
|
||||
procedure Str.64 (#Derived_gen.24, #Derived_gen.25, #Derived_gen.26, #Derived_gen.27):
|
||||
joinpoint Str.390 Str.197 Str.198 Str.199 Str.200:
|
||||
inc Str.198;
|
||||
let Str.391 : [C {}, C {Str, Str}] = CallByName Str.38 Str.198 Str.199;
|
||||
let Str.397 : U8 = 1i64;
|
||||
let Str.398 : U8 = GetTagId Str.391;
|
||||
let Str.399 : Int1 = lowlevel Eq Str.397 Str.398;
|
||||
if Str.399 then
|
||||
dec Str.198;
|
||||
let Str.396 : {Str, Str} = UnionAtIndex (Id 1) (Index 0) Str.391;
|
||||
let Str.202 : Str = StructAtIndex 0 Str.396;
|
||||
let Str.201 : Str = StructAtIndex 1 Str.396;
|
||||
let Str.394 : Str = CallByName Str.3 Str.197 Str.201;
|
||||
dec Str.201;
|
||||
let Str.393 : Str = CallByName Str.3 Str.394 Str.200;
|
||||
jump Str.390 Str.393 Str.202 Str.199 Str.200;
|
||||
else
|
||||
dec Str.98;
|
||||
dec Str.252;
|
||||
dec Str.99;
|
||||
let Str.256 : Str = CallByName Str.3 Str.96 Str.97;
|
||||
dec Str.97;
|
||||
ret Str.256;
|
||||
dec Str.199;
|
||||
dec Str.391;
|
||||
dec Str.200;
|
||||
let Str.395 : Str = CallByName Str.3 Str.197 Str.198;
|
||||
dec Str.198;
|
||||
ret Str.395;
|
||||
in
|
||||
inc #Derived_gen.27;
|
||||
inc #Derived_gen.26;
|
||||
jump Str.390 #Derived_gen.24 #Derived_gen.25 #Derived_gen.26 #Derived_gen.27;
|
||||
|
||||
procedure Str.65 (Str.222, Str.223):
|
||||
let Str.224 : U64 = CallByName Str.36 Str.222;
|
||||
let Str.225 : U64 = CallByName Str.36 Str.223;
|
||||
let Str.226 : U64 = CallByName Num.77 Str.224 Str.225;
|
||||
let Str.417 : U64 = 0i64;
|
||||
let Str.416 : [C , C U64] = CallByName Str.66 Str.222 Str.223 Str.417 Str.226;
|
||||
ret Str.416;
|
||||
|
||||
procedure Str.66 (#Derived_gen.28, #Derived_gen.29, #Derived_gen.30, #Derived_gen.31):
|
||||
joinpoint Str.418 Str.227 Str.228 Str.229 Str.230:
|
||||
let Str.420 : Int1 = CallByName Num.23 Str.229 Str.230;
|
||||
if Str.420 then
|
||||
let Str.424 : Int1 = CallByName Str.70 Str.227 Str.229 Str.228;
|
||||
if Str.424 then
|
||||
dec Str.227;
|
||||
dec Str.228;
|
||||
let Str.425 : [C , C U64] = TagId(1) Str.229;
|
||||
ret Str.425;
|
||||
else
|
||||
let Str.423 : U64 = 1i64;
|
||||
let Str.422 : U64 = CallByName Num.51 Str.229 Str.423;
|
||||
jump Str.418 Str.227 Str.228 Str.422 Str.230;
|
||||
else
|
||||
dec Str.227;
|
||||
dec Str.228;
|
||||
let Str.419 : [C , C U64] = TagId(0) ;
|
||||
ret Str.419;
|
||||
in
|
||||
inc #Derived_gen.29;
|
||||
inc #Derived_gen.30;
|
||||
jump Str.251 #Derived_gen.27 #Derived_gen.28 #Derived_gen.29 #Derived_gen.30;
|
||||
inc #Derived_gen.28;
|
||||
jump Str.418 #Derived_gen.28 #Derived_gen.29 #Derived_gen.30 #Derived_gen.31;
|
||||
|
||||
procedure Str.57 (Str.121, Str.122):
|
||||
let Str.123 : U64 = CallByName Str.36 Str.121;
|
||||
let Str.124 : U64 = CallByName Str.36 Str.122;
|
||||
let Str.125 : U64 = CallByName Num.77 Str.123 Str.124;
|
||||
let Str.278 : U64 = 0i64;
|
||||
let Str.277 : [C , C U64] = CallByName Str.58 Str.121 Str.122 Str.278 Str.125;
|
||||
ret Str.277;
|
||||
procedure Str.69 (Str.253, Str.254):
|
||||
let Str.449 : Int1 = CallByName Num.22 Str.253 Str.254;
|
||||
if Str.449 then
|
||||
ret Str.253;
|
||||
else
|
||||
ret Str.254;
|
||||
|
||||
procedure Str.58 (#Derived_gen.33, #Derived_gen.34, #Derived_gen.35, #Derived_gen.36):
|
||||
joinpoint Str.279 Str.126 Str.127 Str.128 Str.129:
|
||||
let Str.281 : Int1 = CallByName Num.23 Str.128 Str.129;
|
||||
if Str.281 then
|
||||
let Str.285 : Int1 = CallByName Str.62 Str.126 Str.128 Str.127;
|
||||
if Str.285 then
|
||||
dec Str.127;
|
||||
dec Str.126;
|
||||
let Str.286 : [C , C U64] = TagId(1) Str.128;
|
||||
ret Str.286;
|
||||
else
|
||||
let Str.284 : U64 = 1i64;
|
||||
let Str.283 : U64 = CallByName Num.51 Str.128 Str.284;
|
||||
jump Str.279 Str.126 Str.127 Str.283 Str.129;
|
||||
procedure Str.70 (Str.255, Str.256, Str.257):
|
||||
let Str.258 : U64 = CallByName Str.36 Str.255;
|
||||
let Str.259 : U64 = CallByName Str.36 Str.257;
|
||||
let Str.447 : U64 = CallByName Num.53 Str.256 Str.259;
|
||||
let Str.260 : U64 = CallByName Str.69 Str.447 Str.258;
|
||||
let Str.446 : U64 = 0i64;
|
||||
inc Str.255;
|
||||
inc Str.257;
|
||||
let Str.427 : {U64, Str, U64, Str, U64, U64} = Struct {Str.260, Str.255, Str.256, Str.257, Str.446, Str.259};
|
||||
let Str.426 : Int1 = CallByName Str.71 Str.427;
|
||||
ret Str.426;
|
||||
|
||||
procedure Str.71 (Str.261):
|
||||
let Str.267 : U64 = StructAtIndex 0 Str.261;
|
||||
let Str.262 : Str = StructAtIndex 1 Str.261;
|
||||
let Str.263 : U64 = StructAtIndex 2 Str.261;
|
||||
let Str.264 : Str = StructAtIndex 3 Str.261;
|
||||
let Str.265 : U64 = StructAtIndex 4 Str.261;
|
||||
let Str.266 : U64 = StructAtIndex 5 Str.261;
|
||||
let Str.268 : Int1 = CallByName Num.25 Str.263 Str.267;
|
||||
if Str.268 then
|
||||
dec Str.262;
|
||||
dec Str.264;
|
||||
let Str.269 : Int1 = CallByName Bool.9 Str.265 Str.266;
|
||||
ret Str.269;
|
||||
else
|
||||
let Str.442 : U8 = CallByName Str.35 Str.262 Str.263;
|
||||
let Str.443 : U8 = CallByName Str.35 Str.264 Str.265;
|
||||
let Str.270 : Int1 = CallByName Bool.9 Str.442 Str.443;
|
||||
let Str.432 : U64 = StructAtIndex 0 Str.261;
|
||||
let Str.433 : Str = StructAtIndex 1 Str.261;
|
||||
let Str.435 : Str = StructAtIndex 3 Str.261;
|
||||
let Str.437 : U64 = StructAtIndex 5 Str.261;
|
||||
let Str.441 : U64 = 1i64;
|
||||
let Str.439 : U64 = CallByName Num.51 Str.265 Str.441;
|
||||
let Str.440 : U64 = 1i64;
|
||||
let Str.438 : U64 = CallByName Num.51 Str.263 Str.440;
|
||||
let Str.431 : {U64, Str, U64, Str, U64, U64} = Struct {Str.432, Str.433, Str.438, Str.435, Str.439, Str.437};
|
||||
let Str.271 : Int1 = CallByName Str.71 Str.431;
|
||||
if Str.270 then
|
||||
ret Str.271;
|
||||
else
|
||||
dec Str.127;
|
||||
dec Str.126;
|
||||
let Str.280 : [C , C U64] = TagId(0) ;
|
||||
ret Str.280;
|
||||
in
|
||||
inc #Derived_gen.34;
|
||||
inc #Derived_gen.33;
|
||||
jump Str.279 #Derived_gen.33 #Derived_gen.34 #Derived_gen.35 #Derived_gen.36;
|
||||
|
||||
procedure Str.61 (Str.152, Str.153):
|
||||
let Str.309 : Int1 = CallByName Num.22 Str.152 Str.153;
|
||||
if Str.309 then
|
||||
ret Str.152;
|
||||
else
|
||||
ret Str.153;
|
||||
|
||||
procedure Str.62 (Str.154, Str.155, Str.156):
|
||||
let Str.157 : U64 = CallByName Str.36 Str.154;
|
||||
let Str.158 : U64 = CallByName Str.36 Str.156;
|
||||
let Str.307 : U64 = CallByName Num.53 Str.155 Str.158;
|
||||
let Str.159 : U64 = CallByName Str.61 Str.307 Str.157;
|
||||
let Str.306 : U64 = 0i64;
|
||||
inc Str.156;
|
||||
inc Str.154;
|
||||
let Str.288 : {U64, Str, U64, Str, U64, U64} = Struct {Str.159, Str.154, Str.155, Str.156, Str.306, Str.158};
|
||||
let Str.287 : Int1 = CallByName Str.63 Str.288;
|
||||
ret Str.287;
|
||||
|
||||
procedure Str.63 (Str.160):
|
||||
let Str.166 : U64 = StructAtIndex 0 Str.160;
|
||||
let Str.161 : Str = StructAtIndex 1 Str.160;
|
||||
let Str.162 : U64 = StructAtIndex 2 Str.160;
|
||||
let Str.163 : Str = StructAtIndex 3 Str.160;
|
||||
let Str.164 : U64 = StructAtIndex 4 Str.160;
|
||||
let Str.165 : U64 = StructAtIndex 5 Str.160;
|
||||
let Str.167 : Int1 = CallByName Num.25 Str.162 Str.166;
|
||||
if Str.167 then
|
||||
dec Str.163;
|
||||
dec Str.161;
|
||||
let Str.168 : Int1 = CallByName Bool.11 Str.164 Str.165;
|
||||
ret Str.168;
|
||||
else
|
||||
let Str.302 : U8 = CallByName Str.35 Str.161 Str.162;
|
||||
let Str.303 : U8 = CallByName Str.35 Str.163 Str.164;
|
||||
let Str.169 : Int1 = CallByName Bool.11 Str.302 Str.303;
|
||||
let Str.292 : U64 = StructAtIndex 0 Str.160;
|
||||
let Str.293 : Str = StructAtIndex 1 Str.160;
|
||||
let Str.295 : Str = StructAtIndex 3 Str.160;
|
||||
let Str.297 : U64 = StructAtIndex 5 Str.160;
|
||||
let Str.301 : U64 = 1i64;
|
||||
let Str.299 : U64 = CallByName Num.51 Str.164 Str.301;
|
||||
let Str.300 : U64 = 1i64;
|
||||
let Str.298 : U64 = CallByName Num.51 Str.162 Str.300;
|
||||
let Str.291 : {U64, Str, U64, Str, U64, U64} = Struct {Str.292, Str.293, Str.298, Str.295, Str.299, Str.297};
|
||||
let Str.170 : Int1 = CallByName Str.63 Str.291;
|
||||
let Str.290 : Int1 = CallByName Bool.3 Str.169 Str.170;
|
||||
ret Str.290;
|
||||
let Str.429 : Int1 = CallByName Bool.1;
|
||||
ret Str.429;
|
||||
|
||||
procedure Test.0 ():
|
||||
let Test.4 : Str = "bar";
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue