diff --git a/README.md b/README.md
index 630cc13..14cdcb6 100644
--- a/README.md
+++ b/README.md
@@ -747,41 +747,49 @@ You already have seen `length` to find the length of an array or string, `includ
Here is a list of built-in functions available:
-| name | description | example |
-| ----------- | ---------------------------- | ------------------------------------------ |
-| sqrt | square root | `sqrt(2)` |
-| abs | absolute value | `abs(-2)` |
-| log | logarithm | `log(2)` |
-| ln | natural logarithm | `ln(2)` |
-| length | length of an array or string | `length("azert")` |
-| sin | sine of a number | `sin(2)` |
-| cos | cosine of a number | `cos(2)` |
-| tan | tangent of a number | `tan(2.2)` |
-| print | print without a newline | `print("hello")` |
-| println | print with a newline | `println("hello")` |
-| include | include a script | `include("scripts/test_fn.adana")` |
-| require | load a shared object | `require("my_lib.so")` |
-| to_int | cast to int | `to_int("2")`
`to_int(2.2)` |
-| to_hex | format num to hex | `to_hex(2)`
`to_hex(2.2)` |
-| to_binary | format num to binary | `to_binary(2)` |
-| to_double | cast to double | `to_double("2.2")` |
-| to_bool | cast to bool | `to_bool("true")` |
-| to_string | cast to string | `to_string(true)` |
-| drop | drop a variable from context | `drop("myvar")`
`drop(arr[0])` |
-| eval | Evaluate a string as code | `eval("sqrt(9)")` |
-| type_of | Type of variable | `type_of(true)` |
-| is_u8 | Check if u8 | `is_u8(0x1)` |
-| is_i8 | Check if i8 | `is_i8(-1)` |
-| is_int | Check if int | `is_int(512)` |
-| is_double | Check if double | `is_double(1.2)` |
-| is_function | Check if function | `is_function(()=> {1})` |
-| is_struct | Check if struct | `is_struct(struct {})` |
-| is_bool | Check if bool | `is_bool(false)` |
-| is_array | Check if array | `is_bool([1,2])` |
-| is_error | Check if error | `is_error(err)` |
-| make_err | Create an error | `make_err("oops")` |
-| is_match | Check matching regex | `is_match("AaAaAbbBBBb", "(?i)a+(?-i)b+")` |
-| match | Match regex | `match("AaAaAbbBBBb", "(?i)a+(?-i)b+")` |
+| name | description | example |
+| ----------- | ---------------------------- | ------------------------------------------------ |
+| floor | floor double | `floor(4.7)` |
+| ceil | ceil double | `ceil(4.7)` |
+| round | round to places | `round(4.46790, 3)` |
+| sqrt | square root | `sqrt(2)` |
+| abs | absolute value | `abs(-2)` |
+| log | logarithm | `log(2)` |
+| ln | natural logarithm | `ln(2)` |
+| length | length of an array or string | `length("azert")` |
+| sin | sine of a number | `sin(2)` |
+| cos | cosine of a number | `cos(2)` |
+| tan | tangent of a number | `tan(2.2)` |
+| print | print without a newline | `print("hello")` |
+| println | print with a newline | `println("hello")` |
+| include | include a script | `include("scripts/test_fn.adana")` |
+| require | load a shared object | `require("my_lib.so")` |
+| to_int | cast to int | `to_int("2")`
`to_int(2.2)` |
+| to_hex | format num to hex | `to_hex(2)`
`to_hex(2.2)` |
+| to_binary | format num to binary | `to_binary(2)` |
+| to_double | cast to double | `to_double("2.2")` |
+| to_bool | cast to bool | `to_bool("true")` |
+| to_string | cast to string | `to_string(true)` |
+| drop | drop a variable from context | `drop("myvar")`
`drop(arr[0])` |
+| eval | evaluate a string as code | `eval("sqrt(9)")` |
+| type_of | type of variable | `type_of(true)` |
+| is_u8 | check if u8 | `is_u8(0x1)` |
+| is_i8 | check if i8 | `is_i8(-1)` |
+| is_int | check if int | `is_int(512)` |
+| is_double | check if double | `is_double(1.2)` |
+| is_function | check if function | `is_function(()=> {1})` |
+| is_struct | check if struct | `is_struct(struct {})` |
+| is_bool | check if bool | `is_bool(false)` |
+| is_array | check if array | `is_bool([1,2])` |
+| is_error | check if error | `is_error(err)` |
+| make_err | create an error | `make_err("oops")` |
+| is_match | check matching regex | `is_match("AaAaAbbBBBb", "(?i)a+(?-i)b+")` |
+| capitalize | capitalize str | `capitalize("nordine")` |
+| to_upper | to Upper str | `to_upper("hello")` |
+| to_lower | to Lower str | `to_lower("HELLO")` |
+| match | match regex | `match("AaAaAbbBBBb", "(?i)a+(?-i)b+")` |
+| replace | replace | `replace("AaAaAbbBBBb", "(?i)a+(?-i)b+", "xxx")` |
+| replace_all | replace all | `replace_all("AaAaAbbBBBb", "A", "b")` |
#### Matching regexes
diff --git a/adana-script-core/src/lib.rs b/adana-script-core/src/lib.rs
index 9f4e1b7..fd587eb 100644
--- a/adana-script-core/src/lib.rs
+++ b/adana-script-core/src/lib.rs
@@ -2,10 +2,11 @@ pub mod primitive;
use std::collections::BTreeMap;
use constants::{
- BREAK, DROP, ELSE, EULER_NUMBER, FALSE, FOR, IF, IN, IS_ARRAY, IS_BOOL,
- IS_DOUBLE, IS_ERROR, IS_FUNCTION, IS_I8, IS_INT, IS_MATCH, IS_STRUCT,
- IS_U8, MAKE_ERROR, MATCH, MULTILINE, NULL, PI, REQUIRE, RETURN, STRUCT,
- TAU, TO_BINARY, TO_HEX, TRUE, WHILE,
+ BREAK, CAPITALIZE, CEIL, DROP, ELSE, EULER_NUMBER, FALSE, FLOOR, FOR, IF,
+ IN, IS_ARRAY, IS_BOOL, IS_DOUBLE, IS_ERROR, IS_FUNCTION, IS_I8, IS_INT,
+ IS_MATCH, IS_STRUCT, IS_U8, MAKE_ERROR, MATCH, MULTILINE, NULL, PI,
+ REPLACE, REPLACE_ALL, REQUIRE, RETURN, ROUND, STRUCT, TAU, TO_BINARY,
+ TO_HEX, TO_LOWER, TO_UPPER, TRUE, WHILE,
};
use primitive::Primitive;
@@ -48,6 +49,14 @@ pub mod constants {
pub const TO_BINARY: &str = "to_binary";
pub const TO_INT: &str = "to_int";
pub const TO_BOOL: &str = "to_bool";
+ pub const TO_UPPER: &str = "to_upper";
+ pub const TO_LOWER: &str = "to_lower";
+ pub const CAPITALIZE: &str = "capitalize";
+ pub const REPLACE: &str = "replace";
+ pub const REPLACE_ALL: &str = "replace_all";
+ pub const FLOOR: &str = "floor";
+ pub const CEIL: &str = "ceil";
+ pub const ROUND: &str = "round";
pub const TO_DOUBLE: &str = "to_double";
pub const TO_STRING: &str = "to_string";
pub const IS_ERROR: &str = "is_error";
@@ -194,6 +203,14 @@ pub enum BuiltInFunctionType {
ToHex,
ToDouble,
ToBool,
+ ToUpper,
+ ToLower,
+ Capitalize,
+ Replace,
+ ReplaceAll,
+ Floor,
+ Round,
+ Ceil,
ToString,
Tan,
Println,
@@ -293,6 +310,14 @@ impl BuiltInFunctionType {
BuiltInFunctionType::ToBinary => TO_BINARY,
BuiltInFunctionType::ToDouble => TO_DOUBLE,
BuiltInFunctionType::ToBool => TO_BOOL,
+ BuiltInFunctionType::ToUpper => TO_UPPER,
+ BuiltInFunctionType::ToLower => TO_LOWER,
+ BuiltInFunctionType::Capitalize => CAPITALIZE,
+ BuiltInFunctionType::Replace => REPLACE,
+ BuiltInFunctionType::ReplaceAll => REPLACE_ALL,
+ BuiltInFunctionType::Floor => FLOOR,
+ BuiltInFunctionType::Ceil => CEIL,
+ BuiltInFunctionType::Round => ROUND,
BuiltInFunctionType::ToString => TO_STRING,
BuiltInFunctionType::IsError => IS_ERROR,
BuiltInFunctionType::IsU8 => IS_U8,
@@ -352,6 +377,14 @@ pub const FORBIDDEN_VARIABLE_NAME: &[&str] = &[
TO_INT,
TO_DOUBLE,
TO_HEX,
+ CEIL,
+ ROUND,
+ FLOOR,
+ TO_UPPER,
+ TO_LOWER,
+ REPLACE,
+ REPLACE_ALL,
+ CAPITALIZE,
IS_MATCH,
MATCH,
TO_BINARY,
diff --git a/adana-script-core/src/primitive.rs b/adana-script-core/src/primitive.rs
index 26f285a..f3ad1d3 100644
--- a/adana-script-core/src/primitive.rs
+++ b/adana-script-core/src/primitive.rs
@@ -204,9 +204,14 @@ impl Primitive {
Ok(v)
}
}
-pub trait Match {
+pub trait StringManipulation {
fn match_regex(&self, regex: &Primitive) -> Self;
fn is_match(&self, regex: &Primitive) -> Self;
+ fn replace(&self, regex: &Primitive, new_value: &Primitive) -> Self;
+ fn replace_all(&self, regex: &Primitive, new_value: &Primitive) -> Self;
+ fn to_upper(&self) -> Self;
+ fn to_lower(&self) -> Self;
+ fn capitalize(&self) -> Self;
}
pub trait TypeOf {
@@ -302,6 +307,11 @@ pub trait Div {
pub trait Rem {
fn rem(&self, rhs: &Self) -> Self;
}
+pub trait Round {
+ fn floor(&self) -> Self;
+ fn round(&self, decimals: &Self) -> Self;
+ fn ceil(&self) -> Self;
+}
// endregion traits
// region: impl primitive
@@ -1730,12 +1740,78 @@ impl PartialOrd for Primitive {
}
}
-impl Match for Primitive {
+impl Round for Primitive {
+ fn floor(&self) -> Self {
+ match self {
+ Primitive::Ref(l) => {
+ let l = l.read().expect("FLOOR ERROR: could not acquire lock!");
+ l.floor()
+ }
+
+ Primitive::Int(i) => Primitive::Int(*i),
+ Primitive::I8(i) => Primitive::I8(*i),
+ Primitive::U8(i) => Primitive::U8(*i),
+ Primitive::Double(d) => Primitive::Double(d.floor()),
+
+ r => Primitive::Error(format!("illegal call to floor!! {r}")),
+ }
+ }
+
+ fn ceil(&self) -> Self {
+ match self {
+ Primitive::Ref(l) => {
+ let l = l.read().expect("CEIL ERROR: could not acquire lock!");
+ l.floor()
+ }
+
+ Primitive::Int(i) => Primitive::Int(*i),
+ Primitive::I8(i) => Primitive::I8(*i),
+ Primitive::U8(i) => Primitive::U8(*i),
+ Primitive::Double(d) => Primitive::Double(d.ceil()),
+
+ r => Primitive::Error(format!("illegal call to ceil!! {r}")),
+ }
+ }
+
+ fn round(&self, decimals: &Self) -> Self {
+ match (self, decimals) {
+ (Primitive::Ref(s), decimals) => {
+ let l = s.read().expect("ROUND ERROR: could not acquire lock!");
+ l.round(decimals)
+ }
+ (l, Primitive::Ref(decimals)) => {
+ let decimals = decimals
+ .read()
+ .expect("ROUND ERROR: could not acquire lock!");
+ l.round(&decimals)
+ }
+ (v @ Primitive::Double(_), Primitive::U8(u)) => {
+ v.round(&Primitive::Int(*u as i128))
+ }
+ (v @ Primitive::Double(_), Primitive::I8(u)) => {
+ v.round(&Primitive::Int(*u as i128))
+ }
+ (Primitive::Double(x), Primitive::Int(u)) => {
+ if u < &1 || u > &(u32::MAX as i128) {
+ return Primitive::Error(format!(
+ "illegal call to round!! {u}"
+ ));
+ }
+ let decimals = *u as u32;
+ let y = 10i32.pow(decimals) as f64;
+ Primitive::Double((x * y).round() / y)
+ }
+ (p, r) => {
+ Primitive::Error(format!("illegal call to round!! {p} {r}"))
+ }
+ }
+ }
+}
+impl StringManipulation for Primitive {
fn match_regex(&self, regex: &Primitive) -> Self {
match self {
Primitive::Ref(l) => {
- let l =
- l.read().expect("TYPE_OF ERROR: could not acquire lock!");
+ let l = l.read().expect("MATCH ERROR: could not acquire lock!");
l.match_regex(regex)
}
v @ Primitive::String(s) => match regex {
@@ -1805,6 +1881,126 @@ impl Match for Primitive {
p => Primitive::Error(format!("illegal call to is_match!! {p}")),
}
}
+ fn replace(&self, regex: &Primitive, new_value: &Primitive) -> Self {
+ match self {
+ Primitive::Ref(l) => {
+ let l =
+ l.read().expect("REPLACE ERROR: could not acquire lock!");
+ l.match_regex(regex)
+ }
+ v @ Primitive::String(s) => match (regex, new_value) {
+ (Primitive::Ref(regex), new_value) => {
+ let r = regex
+ .read()
+ .expect("REPLACE ERROR: could not acquire lock!");
+ v.replace(&r, new_value)
+ }
+ (regex, Primitive::Ref(new_value)) => {
+ let r = new_value
+ .read()
+ .expect("REPLACE ERROR: could not acquire lock!");
+ v.replace(regex, &r)
+ }
+ (Primitive::String(r), Primitive::String(new_value)) => {
+ match regex::Regex::new(r) {
+ Ok(re) => Primitive::String(
+ re.replace(s, new_value).to_string(),
+ ),
+ Err(e) => {
+ Primitive::Error(format!("replace error: {e}"))
+ }
+ }
+ }
+ (r, l) => {
+ Primitive::Error(format!("bad call to replace! {r} {l}"))
+ }
+ },
+ p => Primitive::Error(format!("illegal call to replace!! {p}")),
+ }
+ }
+ fn replace_all(&self, regex: &Primitive, new_value: &Primitive) -> Self {
+ match self {
+ Primitive::Ref(l) => {
+ let l = l
+ .read()
+ .expect("REPLACE_ALL ERROR: could not acquire lock!");
+ l.match_regex(regex)
+ }
+ v @ Primitive::String(s) => match (regex, new_value) {
+ (Primitive::Ref(regex), new_value) => {
+ let r = regex
+ .read()
+ .expect("REPLACE_ALL ERROR: could not acquire lock!");
+ v.replace(&r, new_value)
+ }
+ (regex, Primitive::Ref(new_value)) => {
+ let r = new_value
+ .read()
+ .expect("REPLACE_ALL ERROR: could not acquire lock!");
+ v.replace(regex, &r)
+ }
+ (Primitive::String(r), Primitive::String(new_value)) => {
+ match regex::Regex::new(r) {
+ Ok(re) => Primitive::String(
+ re.replace_all(s, new_value).to_string(),
+ ),
+ Err(e) => {
+ Primitive::Error(format!("replace_all error: {e}"))
+ }
+ }
+ }
+ (r, l) => Primitive::Error(format!(
+ "bad call to replace_all! {r} {l}"
+ )),
+ },
+ p => {
+ Primitive::Error(format!("illegal call to replace_all!! {p}"))
+ }
+ }
+ }
+ fn to_upper(&self) -> Self {
+ match self {
+ Primitive::Ref(l) => {
+ let l =
+ l.read().expect("TO_UPPER ERROR: could not acquire lock!");
+ l.to_upper()
+ }
+ Primitive::String(s) => Primitive::String(s.to_uppercase()),
+ p => Primitive::Error(format!("illegal call to to_upper!! {p}")),
+ }
+ }
+
+ fn to_lower(&self) -> Self {
+ match self {
+ Primitive::Ref(l) => {
+ let l =
+ l.read().expect("TO_LOWER ERROR: could not acquire lock!");
+ l.to_upper()
+ }
+ Primitive::String(s) => Primitive::String(s.to_lowercase()),
+ p => Primitive::Error(format!("illegal call to to_lower!! {p}")),
+ }
+ }
+
+ fn capitalize(&self) -> Self {
+ match self {
+ Primitive::Ref(l) => {
+ let l = l
+ .read()
+ .expect("CAPITALIZE ERROR: could not acquire lock!");
+ l.to_upper()
+ }
+ Primitive::String(s) => {
+ let mut c = s.chars();
+ let new_s = match c.next() {
+ None => String::new(),
+ Some(f) => f.to_uppercase().chain(c).collect(),
+ };
+ Primitive::String(new_s)
+ }
+ p => Primitive::Error(format!("illegal call to capitalize!! {p}")),
+ }
+ }
}
impl TypeOf for Primitive {
diff --git a/adana-script/src/compute.rs b/adana-script/src/compute.rs
index 5ce7910..89825ad 100644
--- a/adana-script/src/compute.rs
+++ b/adana-script/src/compute.rs
@@ -14,10 +14,10 @@ use super::{ast::to_ast, require_dynamic_lib::require_dynamic_lib};
use adana_script_core::{
primitive::{
Abs, Add, And, Array, BitShift, Cos, DisplayBinary, DisplayHex, Div,
- Logarithm, Match, Mul, Neg, Not, Or, Pow, Primitive, RefPrimitive, Rem,
- Sin, Sqrt, Sub, Tan, ToBool, ToNumber, TypeOf, TYPE_ARRAY, TYPE_BOOL,
- TYPE_DOUBLE, TYPE_ERROR, TYPE_FUNCTION, TYPE_I8, TYPE_INT, TYPE_STRUCT,
- TYPE_U8,
+ Logarithm, Mul, Neg, Not, Or, Pow, Primitive, RefPrimitive, Rem, Round,
+ Sin, Sqrt, StringManipulation, Sub, Tan, ToBool, ToNumber, TypeOf,
+ TYPE_ARRAY, TYPE_BOOL, TYPE_DOUBLE, TYPE_ERROR, TYPE_FUNCTION, TYPE_I8,
+ TYPE_INT, TYPE_STRUCT, TYPE_U8,
},
BuiltInFunctionType, Operator, TreeNodeValue, Value,
};
@@ -462,6 +462,76 @@ fn compute_recur(
adana_script_core::BuiltInFunctionType::TypeOf => {
Ok(v.type_of())
}
+ adana_script_core::BuiltInFunctionType::Floor => {
+ Ok(v.floor())
+ }
+ adana_script_core::BuiltInFunctionType::Ceil => {
+ Ok(v.ceil())
+ }
+ adana_script_core::BuiltInFunctionType::Round => match v {
+ Primitive::Array(arr) => {
+ if arr.is_empty() {
+ return Ok(Primitive::Error(format!(
+ "Invalid argument len {}",
+ arr.len()
+ )));
+ }
+ let s = &arr[0];
+ let decimals = if arr.len() == 2 {
+ &arr[1]
+ } else {
+ &Primitive::Int(2)
+ };
+ Ok(s.round(decimals))
+ }
+ _ => Ok(Primitive::Error(
+ "invalid call to builtin fn match".to_string(),
+ )),
+ },
+ adana_script_core::BuiltInFunctionType::ToUpper => {
+ Ok(v.to_upper())
+ }
+ adana_script_core::BuiltInFunctionType::ToLower => {
+ Ok(v.to_lower())
+ }
+ adana_script_core::BuiltInFunctionType::Capitalize => {
+ Ok(v.capitalize())
+ }
+
+ adana_script_core::BuiltInFunctionType::Replace => {
+ match v {
+ Primitive::Array(arr) => {
+ let [s, r, p] = &arr[0..=2] else {
+ return Ok(Primitive::Error(format!(
+ "Invalid argument len {}",
+ arr.len()
+ )));
+ };
+ Ok(s.replace(r, p))
+ }
+ _ => Ok(Primitive::Error(
+ "invalid call to builtin fn replace"
+ .to_string(),
+ )),
+ }
+ }
+ adana_script_core::BuiltInFunctionType::ReplaceAll => {
+ match v {
+ Primitive::Array(arr) => {
+ let [s, r, p] = &arr[0..=2] else {
+ return Ok(Primitive::Error(format!(
+ "Invalid argument len {}",
+ arr.len()
+ )));
+ };
+ Ok(s.replace_all(r, p))
+ }
+ _ => Ok(Primitive::Error(
+ "invalid call to builtin fn replace_all"
+ .to_string(),
+ )),
+ }
+ }
adana_script_core::BuiltInFunctionType::Match => match v {
Primitive::Array(arr) => {
let [s, r] = &arr[0..=1] else {
diff --git a/adana-script/src/parser.rs b/adana-script/src/parser.rs
index bebddce..3132d1e 100644
--- a/adana-script/src/parser.rs
+++ b/adana-script/src/parser.rs
@@ -450,10 +450,18 @@ fn parse_builtin_fn(s: &str) -> Res {
parse_builtin(BuiltInFunctionType::Log),
parse_builtin(BuiltInFunctionType::Sin),
parse_builtin(BuiltInFunctionType::Cos),
+ parse_builtin(BuiltInFunctionType::ToUpper),
+ parse_builtin(BuiltInFunctionType::ToLower),
+ parse_builtin(BuiltInFunctionType::Capitalize),
+ parse_builtin(BuiltInFunctionType::Ceil),
+ parse_builtin(BuiltInFunctionType::Floor),
)),
alt((
parse_builtin_many_args(BuiltInFunctionType::IsMatch),
parse_builtin_many_args(BuiltInFunctionType::Match),
+ parse_builtin_many_args(BuiltInFunctionType::Replace),
+ parse_builtin_many_args(BuiltInFunctionType::Round),
+ parse_builtin_many_args(BuiltInFunctionType::ReplaceAll),
)), // parse_builtin(BuiltInFunctionType::ReadLines),
))(s)
}
diff --git a/adana-script/src/tests/builtin.rs b/adana-script/src/tests/builtin.rs
index 20238eb..f71a1d5 100644
--- a/adana-script/src/tests/builtin.rs
+++ b/adana-script/src/tests/builtin.rs
@@ -72,6 +72,93 @@ fn test_to_binary() {
assert_eq!(r, Primitive::String("0b1111111".into()));
}
+#[test]
+fn test_floor() {
+ let mut ctx = BTreeMap::new();
+ let r = compute(r#"floor(4.7)"#, &mut ctx, "N/A").unwrap();
+ assert_eq!(Primitive::Double(4.), r);
+}
+
+#[test]
+fn test_ceil() {
+ let mut ctx = BTreeMap::new();
+ let r = compute(r#"ceil(4.7)"#, &mut ctx, "N/A").unwrap();
+ assert_eq!(Primitive::Double(5.), r);
+}
+#[test]
+fn test_round() {
+ let mut ctx = BTreeMap::new();
+ let r = compute(r#"round(4.46790, 2)"#, &mut ctx, "N/A").unwrap();
+ assert_eq!(Primitive::Double(4.47), r);
+ let r = compute(r#"round(4.46790, 3)"#, &mut ctx, "N/A").unwrap();
+ assert_eq!(Primitive::Double(4.468), r);
+}
+#[test]
+fn test_to_lower() {
+ let mut ctx = BTreeMap::new();
+ let r = compute(r#"to_lower("HELLO")"#, &mut ctx, "N/A").unwrap();
+ assert_eq!(Primitive::String("hello".into()), r);
+}
+#[test]
+fn test_to_upper() {
+ let mut ctx = BTreeMap::new();
+ let r = compute(r#"to_upper("hello")"#, &mut ctx, "N/A").unwrap();
+ assert_eq!(Primitive::String("HELLO".into()), r);
+}
+#[test]
+fn test_capitalize() {
+ let mut ctx = BTreeMap::new();
+ let r = compute(r#"capitalize("nordine")"#, &mut ctx, "N/A").unwrap();
+ assert_eq!(Primitive::String("Nordine".into()), r);
+}
+
+#[test]
+fn test_replace() {
+ let mut ctx = BTreeMap::new();
+ let r = compute(r#"replace("Hello, world! Welcome to the world of JavaScript.", "world", "universe")"#, &mut ctx, "N/A").unwrap();
+ assert_eq!(
+ Primitive::String(
+ "Hello, universe! Welcome to the world of JavaScript.".into()
+ ),
+ r
+ );
+ let r = compute(
+ r#"replace("AaAaAbbBBBb", "(?i)a+(?-i)b+", "xxx")"#,
+ &mut ctx,
+ "N/A",
+ )
+ .unwrap();
+ assert_eq!(Primitive::String("xxxBBBb".into()), r);
+ let r = compute(r#"replace("The event is on 12/31/2023. Another date is 31-12-2023. And another one is 2023.12.31.", "(\d{2})/(\d{2})/(\d{4})", "$2-$1-$3")"#, &mut ctx, "N/A").unwrap();
+ assert_eq!(
+ Primitive::String(
+ "The event is on 31-12-2023. Another date is 31-12-2023. And another one is 2023.12.31.".into()
+ ),
+ r
+ );
+}
+
+#[test]
+fn test_replace_all() {
+ let mut ctx = BTreeMap::new();
+ let r = compute(r#"replace_all("Hello, world! Welcome to the world of JavaScript.", "world", "universe")"#, &mut ctx, "N/A").unwrap();
+ assert_eq!(
+ Primitive::String(
+ "Hello, universe! Welcome to the universe of JavaScript.".into()
+ ),
+ r
+ );
+ let r = compute(r#"replace_all("AaAaAbbBBBb", "A", "b")"#, &mut ctx, "N/A")
+ .unwrap();
+ assert_eq!(Primitive::String("bababbbBBBb".into()), r);
+ let r = compute(r#"replace_all("The event is on 12/31/2023. Another date is 31-12-2023. And another one is 12/31/2023.", "(\d{2})/(\d{2})/(\d{4})", "$2-$1-$3")"#, &mut ctx, "N/A").unwrap();
+ assert_eq!(
+ Primitive::String(
+ "The event is on 31-12-2023. Another date is 31-12-2023. And another one is 31-12-2023.".into()
+ ),
+ r
+ );
+}
#[test]
fn test_is_match() {
let mut ctx = BTreeMap::new();
diff --git a/adana-script/src/tests/struc.rs b/adana-script/src/tests/struc.rs
index 05499f8..38506dd 100644
--- a/adana-script/src/tests/struc.rs
+++ b/adana-script/src/tests/struc.rs
@@ -260,6 +260,44 @@ fn test_struct_access_key5() {
let r = compute(expr, &mut ctx, "N/A").unwrap();
assert_eq!(r, Primitive::String("nordine".into()));
}
+#[test]
+fn test_struct_access_key6() {
+ let mut ctx = BTreeMap::new();
+ let expr = r#"
+ struct {
+ other_struct: struct {
+ name: () => {"nordine"},
+ },
+ age: 34,
+ members: ["natalie", "roger","fred"],
+ }.other_struct["name"]()
+
+ "#;
+ let r = compute(expr, &mut ctx, "N/A").unwrap();
+ assert_eq!(r, Primitive::String("nordine".into()));
+}
+
+#[test]
+fn test_struct_access_key7() {
+ let mut ctx = BTreeMap::new();
+ let expr = r#"
+ x= struct {
+ other_struct: struct {
+ name: struct {
+ first_name: () => {"nordine"}
+ last_name: () => {"bittich"}
+ age: 36
+ },
+ },
+ age: 34,
+ members: ["natalie", "roger","fred"],
+ }
+ x.other_struct.name.first_name() + " " + x.other_struct["name"]["last_name"]() + ":" + x.other_struct["name"]["age"]
+
+ "#;
+ let r = compute(expr, &mut ctx, "N/A").unwrap();
+ assert_eq!(r, Primitive::String("nordine bittich:36".into()));
+}
#[test]
fn test_struct_empty() {