feat(tvix/eval): context-aware replaceStrings
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>
This commit is contained in:
parent
cbd22af2b5
commit
96d06031af
1 changed files with 23 additions and 6 deletions
|
@ -919,12 +919,17 @@ mod pure_builtins {
|
||||||
generators::request_force(&co, val.clone()).await;
|
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 res = String::new();
|
||||||
|
|
||||||
let mut i: usize = 0;
|
let mut i: usize = 0;
|
||||||
let mut empty_string_replace = false;
|
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
|
// This can't be implemented using Rust's string.replace() as
|
||||||
// well as a map because we need to handle errors with results
|
// well as a map because we need to handle errors with results
|
||||||
|
@ -935,8 +940,8 @@ mod pure_builtins {
|
||||||
'outer: while i < string.len() {
|
'outer: while i < string.len() {
|
||||||
// Try a match in all the from strings
|
// Try a match in all the from strings
|
||||||
for elem in std::iter::zip(from.iter(), to.iter()) {
|
for elem in std::iter::zip(from.iter(), to.iter()) {
|
||||||
let from = elem.0.to_str()?;
|
let from = elem.0.to_contextful_str()?;
|
||||||
let to = elem.1.to_str()?;
|
let mut to = elem.1.to_contextful_str()?;
|
||||||
|
|
||||||
if i + from.len() > string.len() {
|
if i + from.len() > string.len() {
|
||||||
continue;
|
continue;
|
||||||
|
@ -953,6 +958,9 @@ mod pure_builtins {
|
||||||
if &string[i..i + from.len()] == from.as_str() {
|
if &string[i..i + from.len()] == from.as_str() {
|
||||||
res += &to;
|
res += &to;
|
||||||
i += from.len();
|
i += from.len();
|
||||||
|
if let Some(to_ctx) = to.context_mut() {
|
||||||
|
context = context.join(to_ctx);
|
||||||
|
}
|
||||||
|
|
||||||
// remember if we applied the empty from->to
|
// remember if we applied the empty from->to
|
||||||
empty_string_replace = from.as_str().is_empty();
|
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
|
// Special case when the string is empty or at the string's end
|
||||||
// and one of the from is also empty
|
// and one of the from is also empty
|
||||||
for elem in std::iter::zip(from.iter(), to.iter()) {
|
for elem in std::iter::zip(from.iter(), to.iter()) {
|
||||||
let from = elem.0.to_str()?;
|
let from = elem.0.to_contextful_str()?;
|
||||||
let to = elem.1.to_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() {
|
if from.as_str().is_empty() {
|
||||||
res += &to;
|
res += &to;
|
||||||
|
if let Some(to_ctx) = to.context_mut() {
|
||||||
|
context = context.join(to_ctx);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(Value::String(res.into()))
|
|
||||||
|
// FIXME: consume directly the String.
|
||||||
|
Ok(Value::String(NixString::new_context_from(context, &res)))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[builtin("seq")]
|
#[builtin("seq")]
|
||||||
|
|
Loading…
Add table
Reference in a new issue