From 6961fcc9fa8b7801607ecddc34fa5660ca0a201b Mon Sep 17 00:00:00 2001 From: Ava Hahn Date: Wed, 8 Mar 2023 19:42:08 -0800 Subject: [PATCH] add string split method --- Cargo.toml | 3 +-- src/stl.rs | 11 +++++++++++ src/stl/strings.rs | 33 +++++++++++++++++++++++++++++++ tests/test_lib_str.rs | 45 +++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 90 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index ab899d9..2f93b35 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "relish" version = "0.1.0" -authors = ["Aidan "] +authors = ["Ava "] edition = "2018" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html @@ -9,4 +9,3 @@ edition = "2018" [dependencies] dirs = "3.0" rustyline = "8.2.0" -once_cell = "1.17.1" \ No newline at end of file diff --git a/src/stl.rs b/src/stl.rs index 1fd3e95..ca128d6 100644 --- a/src/stl.rs +++ b/src/stl.rs @@ -74,6 +74,17 @@ pub fn static_stdlib(syms: &mut SymTable) -> Result<(), String> { }, ); + syms.insert( + "split".to_string(), + Symbol { + name: String::from("split"), + args: Args::Strict(vec![Type::String, Type::String]), + conditional_branches: false, + docs: strings::SPLIT_DOCSTRING.to_string(), + value: ValueType::Internal(Rc::new(strings::split_callback)), + }, + ); + syms.insert( "strlen".to_string(), Symbol { diff --git a/src/stl/strings.rs b/src/stl/strings.rs index 896fb51..cefe43e 100644 --- a/src/stl/strings.rs +++ b/src/stl/strings.rs @@ -115,3 +115,36 @@ pub fn contains_callback(ast: &Seg, _syms: &mut SymTable) -> Result Ok(Ctr::Bool(parent_str.contains(&child_str))) } + +pub const SPLIT_DOCSTRING: &str = "Takes two strings. String 1 is a source string and string 2 is a delimiter. +Returns a list of substrings from string 1 that were found delimited by string 2."; + +pub fn split_callback(ast: &Seg, _syms: &mut SymTable) -> Result { + let parent_str: String; + if let Ctr::String(ref s) = *ast.car { + parent_str = s.to_string(); + } else { + return Err("first argument must be a string".to_string()); + } + + let second_arg_obj: &Ctr; + let delim_str: String; + if let Ctr::Seg(ref s) = *ast.cdr { + second_arg_obj = &*s.car; + } else { + return Err("impossible error: needs two arguments".to_string()); + } + + if let Ctr::String(ref s) = &*second_arg_obj { + delim_str = s.clone(); + } else { + return Err("second argument must be a string".to_string()); + } + + let mut ret = Seg::new(); + for substr in parent_str.split(&delim_str) { + ret.append(Box::new(Ctr::String(substr.to_string()))); + } + + Ok(Ctr::Seg(ret)) +} diff --git a/tests/test_lib_str.rs b/tests/test_lib_str.rs index 45a304c..101382f 100644 --- a/tests/test_lib_str.rs +++ b/tests/test_lib_str.rs @@ -181,4 +181,49 @@ mod str_lib_tests { result.to_string(), ); } + + #[test] + fn test_split() { + let document = "(split 'one.two.three' '.')"; + let result = "('one' 'two' 'three')"; + let mut syms = SymTable::new(); + static_stdlib(&mut syms).unwrap(); + dynamic_stdlib(&mut syms).unwrap(); + assert_eq!( + *eval(&lex(&document.to_string()).unwrap(), &mut syms) + .unwrap() + .to_string(), + result.to_string(), + ); + } + + #[test] + fn test_split_big_delim() { + let document = "(split 'one:d:two:d:three' ':d:')"; + let result = "('one' 'two' 'three')"; + let mut syms = SymTable::new(); + static_stdlib(&mut syms).unwrap(); + dynamic_stdlib(&mut syms).unwrap(); + assert_eq!( + *eval(&lex(&document.to_string()).unwrap(), &mut syms) + .unwrap() + .to_string(), + result.to_string(), + ); + } + + #[test] + fn test_splitnt() { + let document = "(split 'one.two.three' '-')"; + let result = "('one.two.three')"; + let mut syms = SymTable::new(); + static_stdlib(&mut syms).unwrap(); + dynamic_stdlib(&mut syms).unwrap(); + assert_eq!( + *eval(&lex(&document.to_string()).unwrap(), &mut syms) + .unwrap() + .to_string(), + result.to_string(), + ); + } }