str.appendScalar

This commit is contained in:
Folkert 2022-07-04 16:27:04 +02:00
parent ab721dd3c1
commit 9c41a4d442
No known key found for this signature in database
GPG key ID: 1F17F6FFD112B97C
10 changed files with 53 additions and 1 deletions

View file

@ -158,6 +158,7 @@ comptime {
exportStrFn(str.substringUnsafe, "substring_unsafe"); exportStrFn(str.substringUnsafe, "substring_unsafe");
exportStrFn(str.getUnsafe, "get_unsafe"); exportStrFn(str.getUnsafe, "get_unsafe");
exportStrFn(str.reserve, "reserve"); exportStrFn(str.reserve, "reserve");
exportStrFn(str.appendScalar, "append_scalar");
exportStrFn(str.strToUtf8C, "to_utf8"); exportStrFn(str.strToUtf8C, "to_utf8");
exportStrFn(str.fromUtf8C, "from_utf8"); exportStrFn(str.fromUtf8C, "from_utf8");
exportStrFn(str.fromUtf8RangeC, "from_utf8_range"); exportStrFn(str.fromUtf8RangeC, "from_utf8_range");

View file

@ -37,7 +37,8 @@ interface Str
splitFirst, splitFirst,
splitLast, splitLast,
walkUtf8WithIndex, walkUtf8WithIndex,
reserve reserve,
appendScalar,
] ]
imports [Bool.{ Bool }, Result.{ Result }] imports [Bool.{ Bool }, Result.{ Result }]
@ -345,3 +346,17 @@ walkUtf8WithIndexHelp = \string, state, step, index, length ->
## Make sure at least some number of bytes fit in this string without reallocating ## Make sure at least some number of bytes fit in this string without reallocating
reserve : Str, Nat -> Str reserve : Str, Nat -> Str
## is UB when the scalar is invalid
appendScalarUnsafe : Str, U32 -> Str
appendScalar : Str, U32 -> Result Str [InvalidScalar]*
appendScalar = \string, scalar ->
if isValidScalar scalar then
Ok (appendScalarUnsafe string scalar)
else
Err InvalidScalar
isValidScalar : U32 -> Bool
isValidScalar = \scalar ->
scalar <= 0xD7FF || (scalar >= 0xE000 && scalar <= 0x10FFFF)

View file

@ -334,6 +334,7 @@ pub const STR_TRIM_LEFT: &str = "roc_builtins.str.trim_left";
pub const STR_TRIM_RIGHT: &str = "roc_builtins.str.trim_right"; pub const STR_TRIM_RIGHT: &str = "roc_builtins.str.trim_right";
pub const STR_GET_UNSAFE: &str = "roc_builtins.str.get_unsafe"; pub const STR_GET_UNSAFE: &str = "roc_builtins.str.get_unsafe";
pub const STR_RESERVE: &str = "roc_builtins.str.reserve"; pub const STR_RESERVE: &str = "roc_builtins.str.reserve";
pub const STR_APPEND_SCALAR: &str = "roc_builtins.str.append_scalar";
pub const DICT_HASH: &str = "roc_builtins.dict.hash"; pub const DICT_HASH: &str = "roc_builtins.dict.hash";
pub const DICT_HASH_STR: &str = "roc_builtins.dict.hash_str"; pub const DICT_HASH_STR: &str = "roc_builtins.dict.hash_str";

View file

@ -84,6 +84,7 @@ pub fn builtin_defs_map(symbol: Symbol, var_store: &mut VarStore) -> Option<Def>
STR_COUNT_UTF8_BYTES => str_count_bytes, STR_COUNT_UTF8_BYTES => str_count_bytes,
STR_SUBSTRING_UNSAFE => str_substring_unsafe, STR_SUBSTRING_UNSAFE => str_substring_unsafe,
STR_RESERVE => str_reserve, STR_RESERVE => str_reserve,
STR_APPEND_SCALAR_UNSAFE => str_append_scalar_unsafe,
STR_FROM_UTF8 => str_from_utf8, STR_FROM_UTF8 => str_from_utf8,
STR_FROM_UTF8_RANGE => str_from_utf8_range, STR_FROM_UTF8_RANGE => str_from_utf8_range,
STR_TO_UTF8 => str_to_utf8, STR_TO_UTF8 => str_to_utf8,
@ -1743,6 +1744,11 @@ fn str_reserve(symbol: Symbol, var_store: &mut VarStore) -> Def {
lowlevel_2(symbol, LowLevel::StrReserve, var_store) lowlevel_2(symbol, LowLevel::StrReserve, var_store)
} }
/// Str.appendScalarUnsafe : Str, U32 -> Str
fn str_append_scalar_unsafe(symbol: Symbol, var_store: &mut VarStore) -> Def {
lowlevel_2(symbol, LowLevel::StrAppendScalar, var_store)
}
/// Str.fromUtf8 : List U8 -> Result Str [BadUtf8 { byteIndex : Nat, problem : Utf8Problem } }]* /// Str.fromUtf8 : List U8 -> Result Str [BadUtf8 { byteIndex : Nat, problem : Utf8Problem } }]*
fn str_from_utf8(symbol: Symbol, var_store: &mut VarStore) -> Def { fn str_from_utf8(symbol: Symbol, var_store: &mut VarStore) -> Def {
let bytes_var = var_store.fresh(); let bytes_var = var_store.fresh();

View file

@ -5364,6 +5364,14 @@ fn run_low_level<'a, 'ctx, 'env>(
let capacity = load_symbol(scope, &args[1]); let capacity = load_symbol(scope, &args[1]);
call_str_bitcode_fn(env, &[string, capacity], bitcode::STR_RESERVE) call_str_bitcode_fn(env, &[string, capacity], bitcode::STR_RESERVE)
} }
StrAppendScalar => {
// Str.appendScalar : Str, U32 -> Str
debug_assert_eq!(args.len(), 2);
let string = load_symbol(scope, &args[0]);
let capacity = load_symbol(scope, &args[1]);
call_str_bitcode_fn(env, &[string, capacity], bitcode::STR_APPEND_SCALAR)
}
StrTrim => { StrTrim => {
// Str.trim : Str -> Str // Str.trim : Str -> Str
debug_assert_eq!(args.len(), 1); debug_assert_eq!(args.len(), 1);

View file

@ -279,6 +279,7 @@ impl<'a> LowLevelCall<'a> {
StrToUtf8 => self.load_args_and_call_zig(backend, bitcode::STR_TO_UTF8), StrToUtf8 => self.load_args_and_call_zig(backend, bitcode::STR_TO_UTF8),
StrReserve => self.load_args_and_call_zig(backend, bitcode::STR_RESERVE), StrReserve => self.load_args_and_call_zig(backend, bitcode::STR_RESERVE),
StrRepeat => self.load_args_and_call_zig(backend, bitcode::STR_REPEAT), StrRepeat => self.load_args_and_call_zig(backend, bitcode::STR_REPEAT),
StrAppendScalar => self.load_args_and_call_zig(backend, bitcode::STR_APPEND_SCALAR),
StrTrim => self.load_args_and_call_zig(backend, bitcode::STR_TRIM), StrTrim => self.load_args_and_call_zig(backend, bitcode::STR_TRIM),
StrSubstringUnsafe => { StrSubstringUnsafe => {
self.load_args_and_call_zig(backend, bitcode::STR_SUBSTRING_UNSAFE) self.load_args_and_call_zig(backend, bitcode::STR_SUBSTRING_UNSAFE)

View file

@ -28,6 +28,7 @@ pub enum LowLevel {
StrGetUnsafe, StrGetUnsafe,
StrSubstringUnsafe, StrSubstringUnsafe,
StrReserve, StrReserve,
StrAppendScalar,
ListLen, ListLen,
ListWithCapacity, ListWithCapacity,
ListGetUnsafe, ListGetUnsafe,
@ -185,6 +186,8 @@ impl LowLevelWrapperType {
Symbol::STR_FROM_UTF8_RANGE => WrapperIsRequired, Symbol::STR_FROM_UTF8_RANGE => WrapperIsRequired,
Symbol::STR_TO_UTF8 => CanBeReplacedBy(StrToUtf8), Symbol::STR_TO_UTF8 => CanBeReplacedBy(StrToUtf8),
Symbol::STR_REPEAT => CanBeReplacedBy(StrRepeat), Symbol::STR_REPEAT => CanBeReplacedBy(StrRepeat),
Symbol::STR_RESERVE => CanBeReplacedBy(StrReserve),
Symbol::STR_APPEND_SCALAR_UNSAFE => CanBeReplacedBy(StrAppendScalar),
Symbol::STR_TRIM => CanBeReplacedBy(StrTrim), Symbol::STR_TRIM => CanBeReplacedBy(StrTrim),
Symbol::STR_TRIM_LEFT => CanBeReplacedBy(StrTrimLeft), Symbol::STR_TRIM_LEFT => CanBeReplacedBy(StrTrimLeft),
Symbol::STR_TRIM_RIGHT => CanBeReplacedBy(StrTrimRight), Symbol::STR_TRIM_RIGHT => CanBeReplacedBy(StrTrimRight),

View file

@ -1197,6 +1197,8 @@ define_builtins! {
39 STR_SPLIT_LAST: "splitLast" 39 STR_SPLIT_LAST: "splitLast"
40 STR_WALK_UTF8_WITH_INDEX: "walkUtf8WithIndex" 40 STR_WALK_UTF8_WITH_INDEX: "walkUtf8WithIndex"
41 STR_RESERVE: "reserve" 41 STR_RESERVE: "reserve"
42 STR_APPEND_SCALAR_UNSAFE: "appendScalarUnsafe"
43 STR_APPEND_SCALAR: "appendScalar"
} }
5 LIST: "List" => { 5 LIST: "List" => {
0 LIST_LIST: "List" imported // the List.List type alias 0 LIST_LIST: "List" imported // the List.List type alias

View file

@ -897,6 +897,7 @@ pub fn lowlevel_borrow_signature(arena: &Bump, op: LowLevel) -> &[bool] {
StrConcat => arena.alloc_slice_copy(&[owned, borrowed]), StrConcat => arena.alloc_slice_copy(&[owned, borrowed]),
StrSubstringUnsafe => arena.alloc_slice_copy(&[owned, irrelevant, irrelevant]), StrSubstringUnsafe => arena.alloc_slice_copy(&[owned, irrelevant, irrelevant]),
StrReserve => arena.alloc_slice_copy(&[owned, irrelevant]), StrReserve => arena.alloc_slice_copy(&[owned, irrelevant]),
StrAppendScalar => arena.alloc_slice_copy(&[owned, irrelevant]),
StrTrim => arena.alloc_slice_copy(&[owned]), StrTrim => arena.alloc_slice_copy(&[owned]),
StrTrimLeft => arena.alloc_slice_copy(&[owned]), StrTrimLeft => arena.alloc_slice_copy(&[owned]),
StrTrimRight => arena.alloc_slice_copy(&[owned]), StrTrimRight => arena.alloc_slice_copy(&[owned]),

View file

@ -1744,3 +1744,17 @@ fn str_walk_utf8_with_index() {
RocList<(u64, u8)> RocList<(u64, u8)>
); );
} }
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn str_append_scalar() {
assert_evals_to!(
indoc!(
r#"
Str.appendScalar "abcd" 'A'
"#
),
RocStr::from("abcdA"),
RocStr
);
}