1
Fork 0
mirror of https://github.com/RGBCube/uutils-coreutils synced 2025-07-29 12:07:46 +00:00

expr: prefix operators length/1, index/3 and substr/3

This commit is contained in:
Roman Gafiyatullin 2015-10-09 18:32:35 +03:00
parent 092e4d1ed4
commit 7b54410557
3 changed files with 56 additions and 3 deletions

View file

@ -105,9 +105,9 @@ separates increasing precedence groups. EXPRESSION may be:
STRING : REGEXP [NOT IMPLEMENTED] anchored pattern match of REGEXP in STRING
match STRING REGEXP [NOT IMPLEMENTED] same as STRING : REGEXP
substr STRING POS LENGTH [NOT IMPLEMENTED] substring of STRING, POS counted from 1
index STRING CHARS [NOT IMPLEMENTED] index in STRING where any CHARS is found, or 0
length STRING [NOT IMPLEMENTED] length of STRING
substr STRING POS LENGTH substring of STRING, POS counted from 1
index STRING CHARS index in STRING where any CHARS is found, or 0
length STRING length of STRING
+ TOKEN interpret TOKEN as a string, even if it is a
keyword like 'match' or an operator like '/'

View file

@ -103,6 +103,9 @@ impl ASTNode {
|a: &String, b: &String| Ok( bool_as_string(a >= b) ),
&operand_values
),
"length" => prefix_operator_length( &operand_values ),
"index" => prefix_operator_index( &operand_values ),
"substr" => prefix_operator_substr( &operand_values ),
_ => Err(format!("operation not implemented: {}", op_type))
}
@ -328,6 +331,55 @@ fn infix_operator_two_ints_or_two_strings<FI, FS>( fi: FI, fs: FS, values: &Vec<
}
}
fn prefix_operator_length( values: &Vec<String> ) -> Result<String, String> {
assert!( values.len() == 1 );
Ok( values[0].len().to_string() )
}
fn prefix_operator_index( values: &Vec<String> ) -> Result<String, String> {
assert!( values.len() == 2 );
let haystack = &values[0];
let needles = &values[1];
let mut current_idx = 0;
for ch_h in haystack.chars() {
current_idx += 1;
for ch_n in needles.chars() {
if ch_n == ch_h {
return Ok( current_idx.to_string() )
}
}
}
Ok( "0".to_string() )
}
fn prefix_operator_substr( values: &Vec<String> ) -> Result<String, String> {
assert!( values.len() == 3 );
let subj = &values[0];
let mut idx = match values[1].parse::<i64>() {
Ok( i ) => i,
Err( _ ) => return Err( "expected integer as POS arg to 'substr'".to_string() ),
};
let mut len = match values[2].parse::<i64>() {
Ok( i ) => i,
Err( _ ) => return Err( "expected integer as LENGTH arg to 'substr'".to_string() ),
};
if idx <= 0 || len <= 0 { return Ok( "".to_string() ) }
let mut out_str = String::new();
for ch in subj.chars() {
idx -= 1;
if idx <= 0 {
if len <= 0 { break; }
len -= 1;
out_str.push( ch );
}
}
Ok( out_str )
}
fn bool_as_int( b: bool ) -> i64 { if b { 1 } else { 0 } }
fn bool_as_string( b: bool ) -> String { if b { "1".to_string() } else { "0".to_string() } }

View file

@ -110,6 +110,7 @@ pub fn strings_to_tokens( strings: &Vec<String> ) -> Result< Vec<(usize, Token)>
"match" => Token::PrefixOp{ arity: 2, value: s.clone() },
"substr" => Token::PrefixOp{ arity: 3, value: s.clone() },
"index" => Token::PrefixOp{ arity: 2, value: s.clone() },
"length" => Token::PrefixOp{ arity: 1, value: s.clone() },
_ => Token::new_value( &s ),
};