Add small string support to the dev backend

This commit is contained in:
Brendan Hansknecht 2021-09-18 14:41:44 -07:00
parent 1fba3702a8
commit 2f24067267
3 changed files with 1017 additions and 7 deletions

View file

@ -9,7 +9,7 @@ use std::marker::PhantomData;
pub mod aarch64;
pub mod x86_64;
const PTR_SIZE: u32 = 64;
const PTR_SIZE: u32 = 8;
pub trait CallConv<GeneralReg: RegTrait, FloatReg: RegTrait> {
const GENERAL_PARAM_REGS: &'static [GeneralReg];
@ -489,6 +489,25 @@ impl<
ASM::mov_freg64_freg64(&mut self.buf, dst_reg, CC::FLOAT_RETURN_REGS[0]);
Ok(())
}
Layout::Builtin(Builtin::Str) => {
if CC::returns_via_arg_pointer(ret_layout)? {
// This will happen on windows, return via pointer here.
Err("FnCall: Returning strings via pointer not yet implemented".to_string())
} else {
let offset = self.claim_stack_size(16)?;
self.symbol_storage_map.insert(
*dst,
SymbolStorage::Base {
offset,
size: 16,
owned: true,
},
);
ASM::mov_base32_reg64(&mut self.buf, offset, CC::GENERAL_RETURN_REGS[0]);
ASM::mov_base32_reg64(&mut self.buf, offset + 8, CC::GENERAL_RETURN_REGS[1]);
Ok(())
}
}
x => Err(format!(
"FnCall: receiving return type, {:?}, is not yet implemented",
x
@ -893,6 +912,35 @@ impl<
ASM::mov_freg64_imm64(&mut self.buf, &mut self.relocs, reg, val);
Ok(())
}
Literal::Str(x) if x.len() < 16 => {
// Load small string.
let reg = self.get_tmp_general_reg()?;
let offset = self.claim_stack_size(16)?;
self.symbol_storage_map.insert(
*sym,
SymbolStorage::Base {
offset,
size: 16,
owned: true,
},
);
let mut bytes = [0; 16];
bytes[..x.len()].copy_from_slice(x.as_bytes());
bytes[15] = (x.len() as u8) | 0b1000_0000;
let mut num_bytes = [0; 8];
num_bytes.copy_from_slice(&bytes[..8]);
let num = i64::from_ne_bytes(num_bytes);
ASM::mov_reg64_imm64(&mut self.buf, reg, num);
ASM::mov_base32_reg64(&mut self.buf, offset, reg);
num_bytes.copy_from_slice(&bytes[8..]);
let num = i64::from_ne_bytes(num_bytes);
ASM::mov_reg64_imm64(&mut self.buf, reg, num);
ASM::mov_base32_reg64(&mut self.buf, offset + 8, reg);
Ok(())
}
x => Err(format!("loading literal, {:?}, is not yet implemented", x)),
}
}
@ -1012,6 +1060,20 @@ impl<
Layout::Builtin(Builtin::Float64) => {
ASM::mov_freg64_base32(&mut self.buf, CC::FLOAT_RETURN_REGS[0], *offset);
}
Layout::Builtin(Builtin::Str) => {
if self.symbol_storage_map.contains_key(&Symbol::RET_POINTER) {
// This will happen on windows, return via pointer here.
Err("Returning strings via pointer not yet implemented".to_string())
} else {
ASM::mov_reg64_base32(&mut self.buf, CC::GENERAL_RETURN_REGS[0], *offset);
ASM::mov_reg64_base32(
&mut self.buf,
CC::GENERAL_RETURN_REGS[1],
*offset + 8,
);
Ok(())
}
}
Layout::Struct(field_layouts) => {
let (offset, size) = (*offset, *size);
// Nothing to do for empty struct

View file

@ -1,12 +1,6 @@
#[macro_use]
extern crate pretty_assertions;
#[macro_use]
extern crate indoc;
extern crate bumpalo;
extern crate libc;
#[macro_use]
mod helpers;

View file

@ -0,0 +1,954 @@
// use roc_std::{RocList, RocStr};
#[macro_use]
extern crate indoc;
#[macro_use]
mod helpers;
#[cfg(all(test, any(target_os = "linux", target_os = "macos"), any(target_arch = "x86_64"/*, target_arch = "aarch64"*/)))]
mod dev_str {
// #[test]
// fn str_split_bigger_delimiter_small_str() {
// assert_evals_to!(
// indoc!(
// r#"
// List.len (Str.split "hello" "JJJJ there")
// "#
// ),
// 1,
// i64
// );
// assert_evals_to!(
// indoc!(
// r#"
// when List.first (Str.split "JJJ" "JJJJ there") is
// Ok str ->
// Str.countGraphemes str
// _ ->
// -1
// "#
// ),
// 3,
// i64
// );
// }
// #[test]
// fn str_split_str_concat_repeated() {
// assert_evals_to!(
// indoc!(
// r#"
// when List.first (Str.split "JJJJJ" "JJJJ there") is
// Ok str ->
// str
// |> Str.concat str
// |> Str.concat str
// |> Str.concat str
// |> Str.concat str
// _ ->
// "Not Str!"
// "#
// ),
// RocStr::from_slice(b"JJJJJJJJJJJJJJJJJJJJJJJJJ"),
// RocStr
// );
// }
// #[test]
// fn str_split_small_str_bigger_delimiter() {
// assert_evals_to!(
// indoc!(
// r#"
// when
// List.first
// (Str.split "JJJ" "0123456789abcdefghi")
// is
// Ok str -> str
// _ -> ""
// "#
// ),
// RocStr::from_slice(b"JJJ"),
// RocStr
// );
// }
// #[test]
// fn str_split_big_str_small_delimiter() {
// assert_evals_to!(
// indoc!(
// r#"
// Str.split "01234567789abcdefghi?01234567789abcdefghi" "?"
// "#
// ),
// RocList::from_slice(&[
// RocStr::from_slice(b"01234567789abcdefghi"),
// RocStr::from_slice(b"01234567789abcdefghi")
// ]),
// RocList<RocStr>
// );
// assert_evals_to!(
// indoc!(
// r#"
// Str.split "01234567789abcdefghi 3ch 01234567789abcdefghi" "3ch"
// "#
// ),
// RocList::from_slice(&[
// RocStr::from_slice(b"01234567789abcdefghi "),
// RocStr::from_slice(b" 01234567789abcdefghi")
// ]),
// RocList<RocStr>
// );
// }
// #[test]
// fn str_split_small_str_small_delimiter() {
// assert_evals_to!(
// indoc!(
// r#"
// Str.split "J!J!J" "!"
// "#
// ),
// RocList::from_slice(&[
// RocStr::from_slice(b"J"),
// RocStr::from_slice(b"J"),
// RocStr::from_slice(b"J")
// ]),
// RocList<RocStr>
// );
// }
// #[test]
// fn str_split_bigger_delimiter_big_strs() {
// assert_evals_to!(
// indoc!(
// r#"
// Str.split
// "string to split is shorter"
// "than the delimiter which happens to be very very long"
// "#
// ),
// RocList::from_slice(&[RocStr::from_slice(b"string to split is shorter")]),
// RocList<RocStr>
// );
// }
// #[test]
// fn str_split_empty_strs() {
// assert_evals_to!(
// indoc!(
// r#"
// Str.split "" ""
// "#
// ),
// RocList::from_slice(&[RocStr::from_slice(b"")]),
// RocList<RocStr>
// );
// }
// #[test]
// fn str_split_minimal_example() {
// assert_evals_to!(
// indoc!(
// r#"
// Str.split "a," ","
// "#
// ),
// RocList::from_slice(&[RocStr::from_slice(b"a"), RocStr::from_slice(b"")]),
// RocList<RocStr>
// )
// }
// #[test]
// fn str_split_small_str_big_delimiter() {
// assert_evals_to!(
// indoc!(
// r#"
// Str.split
// "1---- ---- ---- ---- ----2---- ---- ---- ---- ----"
// "---- ---- ---- ---- ----"
// |> List.len
// "#
// ),
// 3,
// i64
// );
// assert_evals_to!(
// indoc!(
// r#"
// Str.split
// "1---- ---- ---- ---- ----2---- ---- ---- ---- ----"
// "---- ---- ---- ---- ----"
// "#
// ),
// RocList::from_slice(&[
// RocStr::from_slice(b"1"),
// RocStr::from_slice(b"2"),
// RocStr::from_slice(b"")
// ]),
// RocList<RocStr>
// );
// }
// #[test]
// fn str_split_small_str_20_char_delimiter() {
// assert_evals_to!(
// indoc!(
// r#"
// Str.split
// "3|-- -- -- -- -- -- |4|-- -- -- -- -- -- |"
// "|-- -- -- -- -- -- |"
// "#
// ),
// RocList::from_slice(&[
// RocStr::from_slice(b"3"),
// RocStr::from_slice(b"4"),
// RocStr::from_slice(b"")
// ]),
// RocList<RocStr>
// );
// }
// #[test]
// fn str_concat_big_to_big() {
// assert_evals_to!(
// indoc!(
// r#"
// Str.concat
// "First string that is fairly long. Longer strings make for different errors. "
// "Second string that is also fairly long. Two long strings test things that might not appear with short strings."
// "#
// ),
// RocStr::from_slice(b"First string that is fairly long. Longer strings make for different errors. Second string that is also fairly long. Two long strings test things that might not appear with short strings."),
// RocStr
// );
// }
#[test]
fn small_str_literal() {
assert_evals_to!(
"\"JJJJJJJJJJJJJJJ\"",
[
0x4a,
0x4a,
0x4a,
0x4a,
0x4a,
0x4a,
0x4a,
0x4a,
0x4a,
0x4a,
0x4a,
0x4a,
0x4a,
0x4a,
0x4a,
0b1000_1111
],
[u8; 16]
);
}
// #[test]
// fn small_str_zeroed_literal() {
// // Verifies that we zero out unused bytes in the string.
// // This is important so that string equality tests don't randomly
// // fail due to unused memory being there!
// assert_llvm_evals_to!(
// "\"J\"",
// [
// 0x4a,
// 0x00,
// 0x00,
// 0x00,
// 0x00,
// 0x00,
// 0x00,
// 0x00,
// 0x00,
// 0x00,
// 0x00,
// 0x00,
// 0x00,
// 0x00,
// 0x00,
// 0b1000_0001
// ],
// [u8; 16]
// );
// }
// #[test]
// fn small_str_concat_empty_first_arg() {
// assert_llvm_evals_to!(
// r#"Str.concat "" "JJJJJJJJJJJJJJJ""#,
// [
// 0x4a,
// 0x4a,
// 0x4a,
// 0x4a,
// 0x4a,
// 0x4a,
// 0x4a,
// 0x4a,
// 0x4a,
// 0x4a,
// 0x4a,
// 0x4a,
// 0x4a,
// 0x4a,
// 0x4a,
// 0b1000_1111
// ],
// [u8; 16]
// );
// }
// #[test]
// fn small_str_concat_empty_second_arg() {
// assert_llvm_evals_to!(
// r#"Str.concat "JJJJJJJJJJJJJJJ" """#,
// [
// 0x4a,
// 0x4a,
// 0x4a,
// 0x4a,
// 0x4a,
// 0x4a,
// 0x4a,
// 0x4a,
// 0x4a,
// 0x4a,
// 0x4a,
// 0x4a,
// 0x4a,
// 0x4a,
// 0x4a,
// 0b1000_1111
// ],
// [u8; 16]
// );
// }
// #[test]
// fn small_str_concat_small_to_big() {
// assert_evals_to!(
// r#"Str.concat "abc" " this is longer than 15 chars""#,
// RocStr::from_slice(b"abc this is longer than 15 chars"),
// RocStr
// );
// }
// #[test]
// fn small_str_concat_small_to_small_staying_small() {
// assert_llvm_evals_to!(
// r#"Str.concat "J" "JJJJJJJJJJJJJJ""#,
// [
// 0x4a,
// 0x4a,
// 0x4a,
// 0x4a,
// 0x4a,
// 0x4a,
// 0x4a,
// 0x4a,
// 0x4a,
// 0x4a,
// 0x4a,
// 0x4a,
// 0x4a,
// 0x4a,
// 0x4a,
// 0b1000_1111
// ],
// [u8; 16]
// );
// }
// #[test]
// fn small_str_concat_small_to_small_overflow_to_big() {
// assert_evals_to!(
// r#"Str.concat "abcdefghijklm" "nopqrstuvwxyz""#,
// RocStr::from_slice(b"abcdefghijklmnopqrstuvwxyz"),
// RocStr
// );
// }
// #[test]
// fn str_concat_empty() {
// assert_evals_to!(r#"Str.concat "" """#, RocStr::default(), RocStr);
// }
// #[test]
// fn small_str_is_empty() {
// assert_evals_to!(r#"Str.isEmpty "abc""#, false, bool);
// }
// #[test]
// fn big_str_is_empty() {
// assert_evals_to!(
// r#"Str.isEmpty "this is more than 15 chars long""#,
// false,
// bool
// );
// }
// #[test]
// fn empty_str_is_empty() {
// assert_evals_to!(r#"Str.isEmpty """#, true, bool);
// }
// #[test]
// fn str_starts_with() {
// assert_evals_to!(r#"Str.startsWith "hello world" "hell""#, true, bool);
// assert_evals_to!(r#"Str.startsWith "hello world" """#, true, bool);
// assert_evals_to!(r#"Str.startsWith "nope" "hello world""#, false, bool);
// assert_evals_to!(r#"Str.startsWith "hell" "hello world""#, false, bool);
// assert_evals_to!(r#"Str.startsWith "" "hello world""#, false, bool);
// }
// #[test]
// fn str_starts_with_code_point() {
// assert_evals_to!(
// &format!(r#"Str.startsWithCodePt "foobar" {}"#, 'f' as u32),
// true,
// bool
// );
// assert_evals_to!(
// &format!(r#"Str.startsWithCodePt "zoobar" {}"#, 'f' as u32),
// false,
// bool
// );
// }
// #[test]
// fn str_ends_with() {
// assert_evals_to!(r#"Str.endsWith "hello world" "world""#, true, bool);
// assert_evals_to!(r#"Str.endsWith "nope" "hello world""#, false, bool);
// assert_evals_to!(r#"Str.endsWith "" "hello world""#, false, bool);
// }
// #[test]
// fn str_count_graphemes_small_str() {
// assert_evals_to!(r#"Str.countGraphemes "å🤔""#, 2, usize);
// }
// #[test]
// fn str_count_graphemes_three_js() {
// assert_evals_to!(r#"Str.countGraphemes "JJJ""#, 3, usize);
// }
// #[test]
// fn str_count_graphemes_big_str() {
// assert_evals_to!(
// r#"Str.countGraphemes "6🤔å🤔e¥🤔çppkd🙃1jdal🦯asdfa∆ltråø˚waia8918.,🏅jjc""#,
// 45,
// usize
// );
// }
// #[test]
// fn str_starts_with_same_big_str() {
// assert_evals_to!(
// r#"Str.startsWith "123456789123456789" "123456789123456789""#,
// true,
// bool
// );
// }
// #[test]
// fn str_starts_with_different_big_str() {
// assert_evals_to!(
// r#"Str.startsWith "12345678912345678910" "123456789123456789""#,
// true,
// bool
// );
// }
// #[test]
// fn str_starts_with_same_small_str() {
// assert_evals_to!(r#"Str.startsWith "1234" "1234""#, true, bool);
// }
// #[test]
// fn str_starts_with_different_small_str() {
// assert_evals_to!(r#"Str.startsWith "1234" "12""#, true, bool);
// }
// #[test]
// fn str_starts_with_false_small_str() {
// assert_evals_to!(r#"Str.startsWith "1234" "23""#, false, bool);
// }
// #[test]
// fn str_from_int() {
// assert_evals_to!(
// r#"Str.fromInt 1234"#,
// roc_std::RocStr::from_slice("1234".as_bytes()),
// roc_std::RocStr
// );
// assert_evals_to!(
// r#"Str.fromInt 0"#,
// roc_std::RocStr::from_slice("0".as_bytes()),
// roc_std::RocStr
// );
// assert_evals_to!(
// r#"Str.fromInt -1"#,
// roc_std::RocStr::from_slice("-1".as_bytes()),
// roc_std::RocStr
// );
// let max = format!("{}", i64::MAX);
// assert_evals_to!(
// r#"Str.fromInt Num.maxInt"#,
// RocStr::from_slice(max.as_bytes()),
// RocStr
// );
// let min = format!("{}", i64::MIN);
// assert_evals_to!(
// r#"Str.fromInt Num.minInt"#,
// RocStr::from_slice(min.as_bytes()),
// RocStr
// );
// }
// #[test]
// fn str_from_utf8_pass_single_ascii() {
// assert_evals_to!(
// indoc!(
// r#"
// when Str.fromUtf8 [ 97 ] is
// Ok val -> val
// Err _ -> ""
// "#
// ),
// roc_std::RocStr::from_slice("a".as_bytes()),
// roc_std::RocStr
// );
// }
// #[test]
// fn str_from_utf8_pass_many_ascii() {
// assert_evals_to!(
// indoc!(
// r#"
// when Str.fromUtf8 [ 97, 98, 99, 0x7E ] is
// Ok val -> val
// Err _ -> ""
// "#
// ),
// roc_std::RocStr::from_slice("abc~".as_bytes()),
// roc_std::RocStr
// );
// }
// #[test]
// fn str_from_utf8_pass_single_unicode() {
// assert_evals_to!(
// indoc!(
// r#"
// when Str.fromUtf8 [ 0xE2, 0x88, 0x86 ] is
// Ok val -> val
// Err _ -> ""
// "#
// ),
// roc_std::RocStr::from_slice("∆".as_bytes()),
// roc_std::RocStr
// );
// }
// #[test]
// fn str_from_utf8_pass_many_unicode() {
// assert_evals_to!(
// indoc!(
// r#"
// when Str.fromUtf8 [ 0xE2, 0x88, 0x86, 0xC5, 0x93, 0xC2, 0xAC ] is
// Ok val -> val
// Err _ -> ""
// "#
// ),
// roc_std::RocStr::from_slice("∆œ¬".as_bytes()),
// roc_std::RocStr
// );
// }
// #[test]
// fn str_from_utf8_pass_single_grapheme() {
// assert_evals_to!(
// indoc!(
// r#"
// when Str.fromUtf8 [ 0xF0, 0x9F, 0x92, 0x96 ] is
// Ok val -> val
// Err _ -> ""
// "#
// ),
// roc_std::RocStr::from_slice("💖".as_bytes()),
// roc_std::RocStr
// );
// }
// #[test]
// fn str_from_utf8_pass_many_grapheme() {
// assert_evals_to!(
// indoc!(
// r#"
// when Str.fromUtf8 [ 0xF0, 0x9F, 0x92, 0x96, 0xF0, 0x9F, 0xA4, 0xA0, 0xF0, 0x9F, 0x9A, 0x80 ] is
// Ok val -> val
// Err _ -> ""
// "#
// ),
// roc_std::RocStr::from_slice("💖🤠🚀".as_bytes()),
// roc_std::RocStr
// );
// }
// #[test]
// fn str_from_utf8_pass_all() {
// assert_evals_to!(
// indoc!(
// r#"
// when Str.fromUtf8 [ 0xF0, 0x9F, 0x92, 0x96, 98, 0xE2, 0x88, 0x86 ] is
// Ok val -> val
// Err _ -> ""
// "#
// ),
// roc_std::RocStr::from_slice("💖b∆".as_bytes()),
// roc_std::RocStr
// );
// }
// #[test]
// fn str_from_utf8_fail_invalid_start_byte() {
// assert_evals_to!(
// indoc!(
// r#"
// when Str.fromUtf8 [ 97, 98, 0x80, 99 ] is
// Err (BadUtf8 InvalidStartByte byteIndex) ->
// if byteIndex == 2 then
// "a"
// else
// "b"
// _ -> ""
// "#
// ),
// roc_std::RocStr::from_slice("a".as_bytes()),
// roc_std::RocStr
// );
// }
// #[test]
// fn str_from_utf8_fail_unexpected_end_of_sequence() {
// assert_evals_to!(
// indoc!(
// r#"
// when Str.fromUtf8 [ 97, 98, 99, 0xC2 ] is
// Err (BadUtf8 UnexpectedEndOfSequence byteIndex) ->
// if byteIndex == 3 then
// "a"
// else
// "b"
// _ -> ""
// "#
// ),
// roc_std::RocStr::from_slice("a".as_bytes()),
// roc_std::RocStr
// );
// }
// #[test]
// fn str_from_utf8_fail_expected_continuation() {
// assert_evals_to!(
// indoc!(
// r#"
// when Str.fromUtf8 [ 97, 98, 99, 0xC2, 0x00 ] is
// Err (BadUtf8 ExpectedContinuation byteIndex) ->
// if byteIndex == 3 then
// "a"
// else
// "b"
// _ -> ""
// "#
// ),
// roc_std::RocStr::from_slice("a".as_bytes()),
// roc_std::RocStr
// );
// }
// #[test]
// fn str_from_utf8_fail_overlong_encoding() {
// assert_evals_to!(
// indoc!(
// r#"
// when Str.fromUtf8 [ 97, 0xF0, 0x80, 0x80, 0x80 ] is
// Err (BadUtf8 OverlongEncoding byteIndex) ->
// if byteIndex == 1 then
// "a"
// else
// "b"
// _ -> ""
// "#
// ),
// roc_std::RocStr::from_slice("a".as_bytes()),
// roc_std::RocStr
// );
// }
// #[test]
// fn str_from_utf8_fail_codepoint_too_large() {
// assert_evals_to!(
// indoc!(
// r#"
// when Str.fromUtf8 [ 97, 0xF4, 0x90, 0x80, 0x80 ] is
// Err (BadUtf8 CodepointTooLarge byteIndex) ->
// if byteIndex == 1 then
// "a"
// else
// "b"
// _ -> ""
// "#
// ),
// roc_std::RocStr::from_slice("a".as_bytes()),
// roc_std::RocStr
// );
// }
// #[test]
// fn str_from_utf8_fail_surrogate_half() {
// assert_evals_to!(
// indoc!(
// r#"
// when Str.fromUtf8 [ 97, 98, 0xED, 0xA0, 0x80 ] is
// Err (BadUtf8 EncodesSurrogateHalf byteIndex) ->
// if byteIndex == 2 then
// "a"
// else
// "b"
// _ -> ""
// "#
// ),
// roc_std::RocStr::from_slice("a".as_bytes()),
// roc_std::RocStr
// );
// }
// #[test]
// fn str_equality() {
// assert_evals_to!(r#""a" == "a""#, true, bool);
// assert_evals_to!(
// r#""loremipsumdolarsitamet" == "loremipsumdolarsitamet""#,
// true,
// bool
// );
// assert_evals_to!(r#""a" != "b""#, true, bool);
// assert_evals_to!(r#""a" == "b""#, false, bool);
// }
// #[test]
// fn str_clone() {
// use roc_std::RocStr;
// let long = RocStr::from_slice("loremipsumdolarsitamet".as_bytes());
// let short = RocStr::from_slice("x".as_bytes());
// let empty = RocStr::from_slice("".as_bytes());
// debug_assert_eq!(long.clone(), long);
// debug_assert_eq!(short.clone(), short);
// debug_assert_eq!(empty.clone(), empty);
// }
// #[test]
// fn nested_recursive_literal() {
// assert_evals_to!(
// indoc!(
// r#"
// Expr : [ Add Expr Expr, Val I64, Var I64 ]
// expr : Expr
// expr = Add (Add (Val 3) (Val 1)) (Add (Val 1) (Var 1))
// printExpr : Expr -> Str
// printExpr = \e ->
// when e is
// Add a b ->
// "Add ("
// |> Str.concat (printExpr a)
// |> Str.concat ") ("
// |> Str.concat (printExpr b)
// |> Str.concat ")"
// Val v -> "Val " |> Str.concat (Str.fromInt v)
// Var v -> "Var " |> Str.concat (Str.fromInt v)
// printExpr expr
// "#
// ),
// RocStr::from_slice(b"Add (Add (Val 3) (Val 1)) (Add (Val 1) (Var 1))"),
// RocStr
// );
// }
// #[test]
// fn str_join_comma_small() {
// assert_evals_to!(
// r#"Str.joinWith ["1", "2"] ", " "#,
// RocStr::from("1, 2"),
// RocStr
// );
// }
// #[test]
// fn str_join_comma_big() {
// assert_evals_to!(
// r#"Str.joinWith ["10000000", "2000000", "30000000"] ", " "#,
// RocStr::from("10000000, 2000000, 30000000"),
// RocStr
// );
// }
// #[test]
// fn str_join_comma_single() {
// assert_evals_to!(r#"Str.joinWith ["1"] ", " "#, RocStr::from("1"), RocStr);
// }
// #[test]
// fn str_from_float() {
// assert_evals_to!(r#"Str.fromFloat 3.14"#, RocStr::from("3.14"), RocStr);
// }
// #[test]
// fn str_to_utf8() {
// assert_evals_to!(
// r#"Str.toUtf8 "hello""#,
// RocList::from_slice(&[104, 101, 108, 108, 111]),
// RocList<u8>
// );
// assert_evals_to!(
// r#"Str.toUtf8 "this is a long string""#,
// RocList::from_slice(&[
// 116, 104, 105, 115, 32, 105, 115, 32, 97, 32, 108, 111, 110, 103, 32, 115, 116,
// 114, 105, 110, 103
// ]),
// RocList<u8>
// );
// }
// #[test]
// fn str_from_utf8_range() {
// assert_evals_to!(
// indoc!(
// r#"
// bytes = Str.toUtf8 "hello"
// when Str.fromUtf8Range bytes { count: 5, start: 0 } is
// Ok utf8String -> utf8String
// _ -> ""
// "#
// ),
// RocStr::from("hello"),
// RocStr
// );
// }
// #[test]
// fn str_from_utf8_range_slice() {
// assert_evals_to!(
// indoc!(
// r#"
// bytes = Str.toUtf8 "hello"
// when Str.fromUtf8Range bytes { count: 4, start: 1 } is
// Ok utf8String -> utf8String
// _ -> ""
// "#
// ),
// RocStr::from("ello"),
// RocStr
// );
// }
// #[test]
// fn str_from_utf8_range_slice_not_end() {
// assert_evals_to!(
// indoc!(
// r#"
// bytes = Str.toUtf8 "hello"
// when Str.fromUtf8Range bytes { count: 3, start: 1 } is
// Ok utf8String -> utf8String
// _ -> ""
// "#
// ),
// RocStr::from("ell"),
// RocStr
// );
// }
// #[test]
// fn str_from_utf8_range_order_does_not_matter() {
// assert_evals_to!(
// indoc!(
// r#"
// bytes = Str.toUtf8 "hello"
// when Str.fromUtf8Range bytes { start: 1, count: 3 } is
// Ok utf8String -> utf8String
// _ -> ""
// "#
// ),
// RocStr::from("ell"),
// RocStr
// );
// }
// #[test]
// fn str_from_utf8_range_out_of_bounds_start_value() {
// assert_evals_to!(
// indoc!(
// r#"
// bytes = Str.toUtf8 "hello"
// when Str.fromUtf8Range bytes { start: 7, count: 3 } is
// Ok _ -> ""
// Err (BadUtf8 _ _) -> ""
// Err OutOfBounds -> "out of bounds"
// "#
// ),
// RocStr::from("out of bounds"),
// RocStr
// );
// }
// #[test]
// fn str_from_utf8_range_count_too_high() {
// assert_evals_to!(
// indoc!(
// r#"
// bytes = Str.toUtf8 "hello"
// when Str.fromUtf8Range bytes { start: 0, count: 6 } is
// Ok _ -> ""
// Err (BadUtf8 _ _) -> ""
// Err OutOfBounds -> "out of bounds"
// "#
// ),
// RocStr::from("out of bounds"),
// RocStr
// );
// }
// #[test]
// fn str_from_utf8_range_count_too_high_for_start() {
// assert_evals_to!(
// indoc!(
// r#"
// bytes = Str.toUtf8 "hello"
// when Str.fromUtf8Range bytes { start: 4, count: 3 } is
// Ok _ -> ""
// Err (BadUtf8 _ _) -> ""
// Err OutOfBounds -> "out of bounds"
// "#
// ),
// RocStr::from("out of bounds"),
// RocStr
// );
// }
}