diff --git a/README.md b/README.md
index 07b7bc5..630cc13 100644
--- a/README.md
+++ b/README.md
@@ -747,46 +747,45 @@ 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 |
+| ----------- | ---------------------------- | ------------------------------------------ |
+| 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+")` |
#### Matching regexes
-There are two built-in functions for matching a regex against a string. You must use F-string ("""s""")
-notation for the pattern:
+There are two built-in functions for matching a regex against a string:
```python
pattern = """(?i)a+(?-i)b+"""
diff --git a/adana-script/src/string_parser.rs b/adana-script/src/string_parser.rs
index 158326f..4abae7f 100644
--- a/adana-script/src/string_parser.rs
+++ b/adana-script/src/string_parser.rs
@@ -3,6 +3,7 @@ use std::borrow::Cow;
/// copied from https://github.com/rust-bakery/nom/blob/7.1.3/examples/string.rs
use nom::branch::alt;
use nom::bytes::streaming::{is_not, take_while_m_n};
+use nom::character::complete::anychar;
use nom::character::streaming::{char, multispace1};
use nom::combinator::{map, map_opt, map_res, value, verify};
use nom::error::{FromExternalError, ParseError};
@@ -84,6 +85,11 @@ fn parse_escaped_whitespace<'a, E: ParseError<&'a str>>(
) -> IResult<&'a str, &'a str, E> {
preceded(char('\\'), multispace1)(input)
}
+fn parse_escaped_anychar<'a, E: ParseError<&'a str>>(
+ input: &'a str,
+) -> IResult<&'a str, char, E> {
+ preceded(char('\\'), anychar)(input)
+}
/// Parse a non-empty block of text that doesn't include \ or "
fn parse_literal<'a, E: ParseError<&'a str>>(
@@ -108,6 +114,7 @@ enum StringFragment<'a> {
Literal(&'a str),
EscapedChar(char),
EscapedWS,
+ EscapedAnychar(char),
}
/// Combine parse_literal, parse_escaped_whitespace, and parse_escaped_char
@@ -125,6 +132,7 @@ where
map(parse_literal, StringFragment::Literal),
map(parse_escaped_char, StringFragment::EscapedChar),
value(StringFragment::EscapedWS, parse_escaped_whitespace),
+ map(parse_escaped_anychar, StringFragment::EscapedAnychar),
))(input)
}
@@ -152,6 +160,10 @@ where
StringFragment::Literal(s) => string.push_str(s),
StringFragment::EscapedChar(c) => string.push(c),
StringFragment::EscapedWS => {}
+ StringFragment::EscapedAnychar(c) => {
+ string.push('\\');
+ string.push(c)
+ }
}
string
},
diff --git a/adana-script/src/tests/builtin.rs b/adana-script/src/tests/builtin.rs
index 5a315d5..20238eb 100644
--- a/adana-script/src/tests/builtin.rs
+++ b/adana-script/src/tests/builtin.rs
@@ -77,7 +77,7 @@ fn test_is_match() {
let mut ctx = BTreeMap::new();
let r = compute(
r#"
- pattern = """(?i)a+(?-i)b+"""
+ pattern = "(?i)a+(?-i)b+"
text = "AaAaAbbBBBb"
is_match(text, pattern)
@@ -90,7 +90,7 @@ fn test_is_match() {
let mut ctx = BTreeMap::new();
let r = compute(
r#"
- pattern = """(\w+): \$(\d+)"""
+ pattern = "(\w+): \$(\d+)"
text = "Item1: $100, Item2: $200, Item3: $300"
is_match(text, pattern)
@@ -106,7 +106,7 @@ fn test_match() {
let mut ctx = BTreeMap::new();
let r = compute(
r#"
- pattern = """(?i)a+(?-i)b+"""
+ pattern = "(?i)a+(?-i)b+"
text = "AaAaAbbBBBb"
match(text, pattern)
@@ -122,7 +122,7 @@ fn test_match() {
let mut ctx = BTreeMap::new();
let r = compute(
r#"
- pattern = """(\w+): \$(\d+)"""
+ pattern = "(\w+): \$(\d+)"
text = "Item1: $100, Item2: $200, Item3: $300"
match(text, pattern)
diff --git a/adana-script/src/tests/strings.rs b/adana-script/src/tests/strings.rs
index d47b16a..ffc62f5 100644
--- a/adana-script/src/tests/strings.rs
+++ b/adana-script/src/tests/strings.rs
@@ -37,6 +37,18 @@ fn test_string_escape() {
);
}
#[test]
+fn test_string_regex() {
+ let expr = r#"
+ s = "(\w+): \$(\d+)"
+ "#;
+ let mut ctx = BTreeMap::new();
+ let _ = compute(expr, &mut ctx, "N/A").unwrap();
+ assert_eq!(
+ Primitive::String(r#"(\w+): \$(\d+)"#.to_string()),
+ ctx["s"].read().unwrap().clone()
+ );
+}
+#[test]
fn test_string_block_with_parameters() {
let expr = r#"
name = "nordine"