1
Fork 0
mirror of https://github.com/RGBCube/uutils-coreutils synced 2025-07-28 19:47:45 +00:00

Merge pull request #762 from ebfe/expr-and-or

expr: implement '|' and '&'
This commit is contained in:
Heather 2015-12-22 17:20:58 +04:00
commit 9339bbe50d
3 changed files with 83 additions and 1 deletions

View file

@ -125,6 +125,7 @@ TEST_PROGS := \
dirname \ dirname \
echo \ echo \
env \ env \
expr \
factor \ factor \
false \ false \
fold \ fold \

View file

@ -103,6 +103,8 @@ impl ASTNode {
|a: &String, b: &String| Ok( bool_as_string(a >= b) ), |a: &String, b: &String| Ok( bool_as_string(a >= b) ),
&operand_values &operand_values
), ),
"|" => infix_operator_or(&operand_values),
"&" => infix_operator_and(&operand_values),
"length" => prefix_operator_length( &operand_values ), "length" => prefix_operator_length( &operand_values ),
"index" => prefix_operator_index( &operand_values ), "index" => prefix_operator_index( &operand_values ),
"substr" => prefix_operator_substr( &operand_values ), "substr" => prefix_operator_substr( &operand_values ),
@ -331,6 +333,23 @@ fn infix_operator_two_ints_or_two_strings<FI, FS>( fi: FI, fs: FS, values: &Vec<
} }
} }
fn infix_operator_or( values: &Vec<String> ) -> Result<String, String> {
assert!(values.len() == 2);
if value_as_bool(&values[0]) {
Ok(values[0].clone())
} else {
Ok(values[1].clone())
}
}
fn infix_operator_and( values: &Vec<String> ) -> Result<String, String> {
if value_as_bool(&values[0]) && value_as_bool(&values[1]) {
Ok(values[0].clone())
} else {
Ok(0.to_string())
}
}
fn prefix_operator_length( values: &Vec<String> ) -> Result<String, String> { fn prefix_operator_length( values: &Vec<String> ) -> Result<String, String> {
assert!( values.len() == 1 ); assert!( values.len() == 1 );
Ok( values[0].len().to_string() ) Ok( values[0].len().to_string() )
@ -383,4 +402,12 @@ fn prefix_operator_substr( values: &Vec<String> ) -> Result<String, String> {
fn bool_as_int( b: bool ) -> i64 { if b { 1 } else { 0 } } 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() } } fn bool_as_string( b: bool ) -> String { if b { "1".to_string() } else { "0".to_string() } }
fn value_as_bool( s: &str ) -> bool {
if s.len() == 0 {
return false
}
match s.parse::<i64>() {
Ok(n) => n != 0,
Err(_) => true,
}
}

54
tests/expr.rs Normal file
View file

@ -0,0 +1,54 @@
#[macro_use]
mod common;
use common::util::*;
static UTIL_NAME: &'static str = "expr";
#[test]
fn test_simple_arithmetic() {
let (_, mut ucmd) = testing(UTIL_NAME);
let out = ucmd.args(&["1", "+", "1"]).run().stdout;
assert_eq!(out, "2\n");
let (_, mut ucmd) = testing(UTIL_NAME);
let out = ucmd.args(&["1", "-", "1"]).run().stdout;
assert_eq!(out, "0\n");
let (_, mut ucmd) = testing(UTIL_NAME);
let out = ucmd.args(&["3", "*", "2"]).run().stdout;
assert_eq!(out, "6\n");
let (_, mut ucmd) = testing(UTIL_NAME);
let out = ucmd.args(&["4", "/", "2"]).run().stdout;
assert_eq!(out, "2\n");
}
#[test]
fn test_parenthesis() {
let (_, mut ucmd) = testing(UTIL_NAME);
let out = ucmd.args(&["(", "1", "+", "1", ")", "*", "2"]).run().stdout;
assert_eq!(out, "4\n");
}
#[test]
fn test_or() {
let (_, mut ucmd) = testing(UTIL_NAME);
let out = ucmd.args(&["0", "|", "foo"]).run().stdout;
assert_eq!(out, "foo\n");
let (_, mut ucmd) = testing(UTIL_NAME);
let out = ucmd.args(&["foo", "|", "bar"]).run().stdout;
assert_eq!(out, "foo\n");
}
#[test]
fn test_and() {
let (_, mut ucmd) = testing(UTIL_NAME);
let out = ucmd.args(&["foo", "&", "1"]).run().stdout;
assert_eq!(out, "foo\n");
let (_, mut ucmd) = testing(UTIL_NAME);
let out = ucmd.args(&["", "&", "1"]).run().stdout;
assert_eq!(out, "0\n");
}