about summary refs log tree commit diff
path: root/tvix/eval/src/builtins/mod.rs
diff options
context:
space:
mode:
Diffstat (limited to 'tvix/eval/src/builtins/mod.rs')
-rw-r--r--tvix/eval/src/builtins/mod.rs38
1 files changed, 38 insertions, 0 deletions
diff --git a/tvix/eval/src/builtins/mod.rs b/tvix/eval/src/builtins/mod.rs
index 7f55c90c15ad..a6fcb8742c56 100644
--- a/tvix/eval/src/builtins/mod.rs
+++ b/tvix/eval/src/builtins/mod.rs
@@ -632,6 +632,44 @@ fn pure_builtins() -> Vec<Builtin> {
             // we just return the second and ignore the first
             Ok(args.pop().unwrap())
         }),
+        Builtin::new(
+            "split",
+            &[true, true],
+            |mut args: Vec<Value>, _: &mut VM| {
+                let s = args.pop().unwrap().to_str()?;
+                let text = s.as_str();
+                let re = args.pop().unwrap().to_str()?;
+                let re: Regex = Regex::new(re.as_str()).unwrap();
+                let mut capture_locations = re.capture_locations();
+                let num_captures = capture_locations.len();
+                let mut ret = NixList::new();
+                let mut pos = 0;
+
+                while let Some(thematch) = re.captures_read_at(&mut capture_locations, text, pos) {
+                    // push the unmatched characters preceding the match
+                    ret.push(Value::from(&text[pos..thematch.start()]));
+
+                    // Push a list with one element for each capture
+                    // group in the regex, containing the characters
+                    // matched by that capture group, or null if no match.
+                    // We skip capture 0; it represents the whole match.
+                    let v: Vec<Value> = (1..num_captures)
+                        .map(|i| capture_locations.get(i))
+                        .map(|o| {
+                            o.map(|(start, end)| Value::from(&text[start..end]))
+                                .unwrap_or(Value::Null)
+                        })
+                        .collect();
+                    ret.push(Value::List(NixList::from(v)));
+                    pos = thematch.end();
+                }
+
+                // push the unmatched characters following the last match
+                ret.push(Value::from(&text[pos..]));
+
+                Ok(Value::List(ret))
+            },
+        ),
         Builtin::new("sort", &[true, true], |args: Vec<Value>, vm: &mut VM| {
             let mut list = args[1].to_list()?;
             let comparator = &args[0];