Add iterator support for strings.
This commit is contained in:
parent
4603f8026f
commit
ff37e02443
16
README.md
16
README.md
@ -1499,6 +1499,11 @@ record == "Bob X. Davis: age 42 ❤\n";
|
||||
"Davis" in record == true;
|
||||
'X' in record == true;
|
||||
'C' in record == false;
|
||||
|
||||
// Strings can be iterated with a 'for' statement, yielding characters
|
||||
for ch in record {
|
||||
print(ch);
|
||||
}
|
||||
```
|
||||
|
||||
The maximum allowed length of a string can be controlled via `Engine::set_max_string_size`
|
||||
@ -2011,9 +2016,18 @@ loop {
|
||||
Iterating through a range or an [array] is provided by the `for` ... `in` loop.
|
||||
|
||||
```rust
|
||||
let array = [1, 3, 5, 7, 9, 42];
|
||||
// Iterate through string, yielding characters
|
||||
let s = "hello, world!";
|
||||
|
||||
for ch in s {
|
||||
if ch > 'z' { continue; } // skip to the next iteration
|
||||
print(ch);
|
||||
if x == '@' { break; } // break out of for loop
|
||||
}
|
||||
|
||||
// Iterate through array
|
||||
let array = [1, 3, 5, 7, 9, 42];
|
||||
|
||||
for x in array {
|
||||
if x > 10 { continue; } // skip to the next iteration
|
||||
print(x);
|
||||
|
@ -125,7 +125,7 @@ fn main() {
|
||||
|
||||
match engine
|
||||
.compile_with_scope(&scope, &script)
|
||||
.map_err(|err| err.into())
|
||||
.map_err(Into::into)
|
||||
.and_then(|r| {
|
||||
ast_u = r.clone();
|
||||
|
||||
|
@ -2265,14 +2265,14 @@ fn run_builtin_binary_op(
|
||||
|
||||
#[cfg(not(feature = "unchecked"))]
|
||||
match op {
|
||||
"+" => return add(x, y).map(Into::<Dynamic>::into).map(Some),
|
||||
"-" => return sub(x, y).map(Into::<Dynamic>::into).map(Some),
|
||||
"*" => return mul(x, y).map(Into::<Dynamic>::into).map(Some),
|
||||
"/" => return div(x, y).map(Into::<Dynamic>::into).map(Some),
|
||||
"%" => return modulo(x, y).map(Into::<Dynamic>::into).map(Some),
|
||||
"~" => return pow_i_i(x, y).map(Into::<Dynamic>::into).map(Some),
|
||||
">>" => return shr(x, y).map(Into::<Dynamic>::into).map(Some),
|
||||
"<<" => return shl(x, y).map(Into::<Dynamic>::into).map(Some),
|
||||
"+" => return add(x, y).map(Into::into).map(Some),
|
||||
"-" => return sub(x, y).map(Into::into).map(Some),
|
||||
"*" => return mul(x, y).map(Into::into).map(Some),
|
||||
"/" => return div(x, y).map(Into::into).map(Some),
|
||||
"%" => return modulo(x, y).map(Into::into).map(Some),
|
||||
"~" => return pow_i_i(x, y).map(Into::into).map(Some),
|
||||
">>" => return shr(x, y).map(Into::into).map(Some),
|
||||
"<<" => return shl(x, y).map(Into::into).map(Some),
|
||||
_ => (),
|
||||
}
|
||||
|
||||
@ -2283,9 +2283,9 @@ fn run_builtin_binary_op(
|
||||
"*" => return Ok(Some((x * y).into())),
|
||||
"/" => return Ok(Some((x / y).into())),
|
||||
"%" => return Ok(Some((x % y).into())),
|
||||
"~" => return pow_i_i_u(x, y).map(Into::<Dynamic>::into).map(Some),
|
||||
">>" => return shr_u(x, y).map(Into::<Dynamic>::into).map(Some),
|
||||
"<<" => return shl_u(x, y).map(Into::<Dynamic>::into).map(Some),
|
||||
"~" => return pow_i_i_u(x, y).map(Into::into).map(Some),
|
||||
">>" => return shr_u(x, y).map(Into::into).map(Some),
|
||||
"<<" => return shl_u(x, y).map(Into::into).map(Some),
|
||||
_ => (),
|
||||
}
|
||||
|
||||
@ -2359,7 +2359,7 @@ fn run_builtin_binary_op(
|
||||
"*" => return Ok(Some((x * y).into())),
|
||||
"/" => return Ok(Some((x / y).into())),
|
||||
"%" => return Ok(Some((x % y).into())),
|
||||
"~" => return pow_f_f(x, y).map(Into::<Dynamic>::into).map(Some),
|
||||
"~" => return pow_f_f(x, y).map(Into::into).map(Some),
|
||||
"==" => return Ok(Some((x == y).into())),
|
||||
"!=" => return Ok(Some((x != y).into())),
|
||||
">" => return Ok(Some((x > y).into())),
|
||||
|
@ -15,6 +15,7 @@ use crate::stdlib::{
|
||||
fmt::Display,
|
||||
format,
|
||||
string::{String, ToString},
|
||||
vec::Vec,
|
||||
};
|
||||
|
||||
fn prepend<T: Display>(x: T, y: ImmutableString) -> FuncReturn<ImmutableString> {
|
||||
@ -290,4 +291,12 @@ def_package!(crate:MoreStringPackage:"Additional string utilities, including str
|
||||
Ok(())
|
||||
},
|
||||
);
|
||||
|
||||
// Register string iterator
|
||||
lib.set_iter(
|
||||
TypeId::of::<ImmutableString>(),
|
||||
|arr| Box::new(
|
||||
arr.cast::<ImmutableString>().chars().collect::<Vec<_>>().into_iter().map(Into::into)
|
||||
) as Box<dyn Iterator<Item = Dynamic>>,
|
||||
);
|
||||
});
|
||||
|
20
tests/for.rs
20
tests/for.rs
@ -30,6 +30,26 @@ fn test_for_array() -> Result<(), Box<EvalAltResult>> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_for_string() -> Result<(), Box<EvalAltResult>> {
|
||||
let engine = Engine::new();
|
||||
|
||||
let script = r#"
|
||||
let s = "hello";
|
||||
let sum = 0;
|
||||
|
||||
for ch in s {
|
||||
sum += ch.to_int();
|
||||
}
|
||||
|
||||
sum
|
||||
"#;
|
||||
|
||||
assert_eq!(engine.eval::<INT>(script)?, 532);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "no_object"))]
|
||||
#[cfg(not(feature = "no_index"))]
|
||||
#[test]
|
||||
|
Loading…
Reference in New Issue
Block a user