Permalink
Browse files

Implement Length Methods

Implements the `$len()` and `$len_bytes()` methods for strings, and
the `@len()` method for arrays. The len method for arrays returns
the number of elements in the array. The len method for strings
returns the number of graphemes in the string, whereas the
len_bytes method returns the number of bytes the string occupies.
  • Loading branch information...
mmstick committed Jun 20, 2017
1 parent 7f2deeb commit 14d6b336ca342df7dc012f7168f6d731f301e956
Showing with 91 additions and 1 deletion.
  1. +12 −0 examples/methods.ion
  2. +46 −0 examples/methods.out
  3. +1 −0 src/parser/mod.rs
  4. +23 −1 src/parser/shell_expand/mod.rs
  5. +9 −0 src/parser/shell_expand/words.rs
View
@@ -5,3 +5,15 @@ echo $space_string
echo $comma_string
echo @split(space_string)
echo @split(comma_string, ', ')
let array = ["one two" "three four" "five six" "seven eight" "nine ten"]
echo @len(array)
for element in 0..@len(array)
echo @array[$element]
end
let string = "one 😉😉😉 two 😉😉😉 three 😉😉😉 four 😉😉😉 five"
echo $len(string) $len_bytes(string)
for grapheme in 0..$len(string)
echo $string[$grapheme]
end
View
@@ -2,3 +2,49 @@ one two three four
one, two, three, four
one two three four
one two three four
5
one two
three four
five six
seven eight
nine ten
39 75
o
n
e
😉
😉
😉
t
w
o
😉
😉
😉
t
h
r
e
e
😉
😉
😉
f
o
u
r
😉
😉
😉
f
i
v
e
View
@@ -2,6 +2,7 @@
macro_rules! get_expanders {
($vars:expr, $dir_stack:expr) => {
ExpanderFunctions {
vars: $vars,
tilde: &|tilde: &str| $vars.tilde_expansion(tilde, $dir_stack),
array: &|array: &str, selection : Select| {
use std::iter::FromIterator;
@@ -12,11 +12,13 @@ use glob::glob;
use self::braces::BraceToken;
use self::ranges::parse_range;
pub use self::words::{WordIterator, WordToken, Select, Index, Range};
use shell::variables::Variables;
use std::io::{self, Write};
use types::*;
pub struct ExpanderFunctions<'f> {
pub vars: &'f Variables,
pub tilde: &'f Fn(&str) -> Option<String>,
pub array: &'f Fn(&str, Select) -> Option<Array>,
pub variable: &'f Fn(&str, bool) -> Option<Value>,
@@ -225,6 +227,12 @@ pub fn expand_tokens<'a>(token_buffer: &[WordToken], expand_func: &'a ExpanderFu
"join" => if let Some(array) = (expand_func.array)(variable, Select::All) {
slice_string(&mut output, &array.join(pattern), index);
},
"len" => output.push_str(&UnicodeSegmentation::graphemes (
expand_func.vars.get_var_or_empty(variable).as_str(), true
).count().to_string()),
"len_bytes" => output.push_str(
&expand_func.vars.get_var_or_empty(variable).len().to_string()
),
_ => {
let stderr = io::stderr();
let mut stderr = stderr.lock();
@@ -342,7 +350,14 @@ pub fn expand_tokens<'a>(token_buffer: &[WordToken], expand_func: &'a ExpanderFu
}
},
WordToken::ArrayMethod(ref array_method) => {
return array_method.handle_as_array(expand_func);
return if array_method.returns_array() {
array_method.handle_as_array(expand_func)
} else {
let mut output = String::new();
array_method.handle(&mut output, expand_func);
Array::from_vec(vec![output])
};
},
_ => ()
}
@@ -418,6 +433,12 @@ pub fn expand_tokens<'a>(token_buffer: &[WordToken], expand_func: &'a ExpanderFu
"join" => if let Some(array) = (expand_func.array)(variable, Select::All) {
slice_string(&mut output, &array.join(pattern), index);
},
"len" => output.push_str(&UnicodeSegmentation::graphemes (
expand_func.vars.get_var_or_empty(variable).as_str(), true
).count().to_string()),
"len_bytes" => output.push_str(
&expand_func.vars.get_var_or_empty(variable).len().to_string()
),
_ => {
let stderr = io::stderr();
let mut stderr = stderr.lock();
@@ -476,6 +497,7 @@ mod test {
macro_rules! functions {
() => {
ExpanderFunctions {
vars: &Variables::default(),
tilde: &|_| None,
array: &|_, _| None,
variable: &|variable: &str, _| match variable {
@@ -179,8 +179,15 @@ pub struct ArrayMethod<'a> {
}
impl<'a> ArrayMethod<'a> {
pub fn returns_array(&self) -> bool {
self.method == "split"
}
pub fn handle(&self, current: &mut String, expand_func: &ExpanderFunctions) {
match self.method {
"len" => match expand_func.vars.get_array(self.variable) {
Some(array) => current.push_str(&array.len().to_string()),
None => current.push_str("0")
},
"split" => if let Some(variable) = (expand_func.variable)(self.variable, false) {
match (&self.pattern, self.selection) {
(&Pattern::StringPattern(pattern), Select::All) => current.push_str (
@@ -1025,10 +1032,12 @@ impl<'a> Iterator for WordIterator<'a> {
#[cfg(test)]
mod tests {
use super::*;
use shell::variables::Variables;
macro_rules! functions {
() => {
ExpanderFunctions {
vars: &Variables::default(),
tilde: &|_| None,
array: &|_, _| None,
variable: &|_, _| None,

0 comments on commit 14d6b33

Please sign in to comment.