diff options
author | Ryan Lahfa <tvl@lahfa.xyz> | 2023-12-26T00·15+0100 |
---|---|---|
committer | clbot <clbot@tvl.fyi> | 2024-01-03T18·16+0000 |
commit | 96d06031affefeb0ee312e5fa5a6fcea29a7dff9 (patch) | |
tree | 6b5764f84d839893f5e5e9f57c480918c855c79b /tvix | |
parent | cbd22af2b5577d588815e8b59b27c98befc57c46 (diff) |
feat(tvix/eval): context-aware `replaceStrings` r/7330
And it also preserve the original context if it exists. Change-Id: I904f7c13b7f003a267aace6301723780fccaafb7 Reviewed-on: https://cl.tvl.fyi/c/depot/+/10434 Tested-by: BuildkiteCI Reviewed-by: tazjin <tazjin@tvl.su> Autosubmit: raitobezarius <tvl@lahfa.xyz>
Diffstat (limited to 'tvix')
-rw-r--r-- | tvix/eval/src/builtins/mod.rs | 29 |
1 files changed, 23 insertions, 6 deletions
diff --git a/tvix/eval/src/builtins/mod.rs b/tvix/eval/src/builtins/mod.rs index fa84afb70af6..246efff12b77 100644 --- a/tvix/eval/src/builtins/mod.rs +++ b/tvix/eval/src/builtins/mod.rs @@ -919,12 +919,17 @@ mod pure_builtins { generators::request_force(&co, val.clone()).await; } - let string = s.to_str()?; + let mut string = s.to_contextful_str()?; let mut res = String::new(); let mut i: usize = 0; let mut empty_string_replace = false; + let mut context = NixContext::new(); + + if let Some(string_context) = string.context_mut() { + context = context.join(string_context); + } // This can't be implemented using Rust's string.replace() as // well as a map because we need to handle errors with results @@ -935,8 +940,8 @@ mod pure_builtins { 'outer: while i < string.len() { // Try a match in all the from strings for elem in std::iter::zip(from.iter(), to.iter()) { - let from = elem.0.to_str()?; - let to = elem.1.to_str()?; + let from = elem.0.to_contextful_str()?; + let mut to = elem.1.to_contextful_str()?; if i + from.len() > string.len() { continue; @@ -953,6 +958,9 @@ mod pure_builtins { if &string[i..i + from.len()] == from.as_str() { res += &to; i += from.len(); + if let Some(to_ctx) = to.context_mut() { + context = context.join(to_ctx); + } // remember if we applied the empty from->to empty_string_replace = from.as_str().is_empty(); @@ -973,15 +981,24 @@ mod pure_builtins { // Special case when the string is empty or at the string's end // and one of the from is also empty for elem in std::iter::zip(from.iter(), to.iter()) { - let from = elem.0.to_str()?; - let to = elem.1.to_str()?; + let from = elem.0.to_contextful_str()?; + // We mutate `to` by consuming its context + // if we perform a successful replacement. + // Therefore, it's fine if `to` was mutate and we reuse it here. + // We don't need to merge again the context, it's already in the right state. + let mut to = elem.1.to_contextful_str()?; if from.as_str().is_empty() { res += &to; + if let Some(to_ctx) = to.context_mut() { + context = context.join(to_ctx); + } break; } } - Ok(Value::String(res.into())) + + // FIXME: consume directly the String. + Ok(Value::String(NixString::new_context_from(context, &res))) } #[builtin("seq")] |