diff options
author | William Carroll <wpcarro@gmail.com> | 2022-09-06T21·33-0700 |
---|---|---|
committer | clbot <clbot@tvl.fyi> | 2022-09-19T00·51+0000 |
commit | 2fe18e44860ad97a88d488590c40cf610a274c1d (patch) | |
tree | 327fc1ba435528ba944efe0e9d99bd0b96a9edc3 /tvix/eval/src/builtins/mod.rs | |
parent | 0c75ce2d3d1cf806a9c6330619928739a6ffe98a (diff) |
feat(tvix/eval): Support builtins.substring r/4916
Nix's `builtins.substring`: - doesn't accept negative indexes for `beg` or `end`. Compare the error messages for: - `builtins.substring -3 5 "testing"` - `builtins.substring 3 -5 "testing"` - `builtins.substring -3 -5 "testing"` - returns an empty string when `beg >= end` - allows `end` to exceed the length of the input string Change-Id: I83af7a099d81b6d537ebe5029d946c7031cb7113 Reviewed-on: https://cl.tvl.fyi/c/depot/+/6555 Reviewed-by: wpcarro <wpcarro@gmail.com> Autosubmit: wpcarro <wpcarro@gmail.com> Reviewed-by: tazjin <tazjin@tvl.su> Tested-by: BuildkiteCI
Diffstat (limited to 'tvix/eval/src/builtins/mod.rs')
-rw-r--r-- | tvix/eval/src/builtins/mod.rs | 29 |
1 files changed, 29 insertions, 0 deletions
diff --git a/tvix/eval/src/builtins/mod.rs b/tvix/eval/src/builtins/mod.rs index aeffca49950d..4bcaaf7a00e5 100644 --- a/tvix/eval/src/builtins/mod.rs +++ b/tvix/eval/src/builtins/mod.rs @@ -4,6 +4,7 @@ //! available builtins in Nix. use std::{ + cmp, collections::{BTreeMap, HashMap}, path::PathBuf, rc::Rc, @@ -192,6 +193,34 @@ fn pure_builtins() -> Vec<Builtin> { let a = args.pop().unwrap(); arithmetic_op!(a, b, -) }), + Builtin::new("substring", 3, |args, vm| { + let beg = args[0].force(vm)?.as_int()?; + let len = args[1].force(vm)?.as_int()?; + let x = args[2].force(vm)?.to_str()?; + + if beg < 0 { + return Err(ErrorKind::IndexOutOfBounds { index: beg }); + } + let beg = beg as usize; + + // Nix doesn't assert that the length argument is + // non-negative when the starting index is GTE the + // string's length. + if beg >= x.as_str().len() { + return Ok(Value::String("".into())); + } + + if len < 0 { + return Err(ErrorKind::NegativeLength { length: len }); + } + + let len = len as usize; + let end = cmp::min(beg + len, x.as_str().len()); + + Ok(Value::String( + x.as_str()[(beg as usize)..(end as usize)].into(), + )) + }), Builtin::new("throw", 1, |mut args, _| { return Err(ErrorKind::Throw( args.pop().unwrap().to_str()?.as_str().to_owned(), |