diff --git a/Makefile b/Makefile index 89cdfeb24..97d389d7c 100644 --- a/Makefile +++ b/Makefile @@ -125,6 +125,7 @@ TEST_PROGS := \ dirname \ echo \ env \ + expr \ factor \ false \ fold \ diff --git a/src/expr/syntax_tree.rs b/src/expr/syntax_tree.rs index 53819974d..698564c72 100644 --- a/src/expr/syntax_tree.rs +++ b/src/expr/syntax_tree.rs @@ -103,6 +103,8 @@ impl ASTNode { |a: &String, b: &String| Ok( bool_as_string(a >= b) ), &operand_values ), + "|" => infix_operator_or(&operand_values), + "&" => infix_operator_and(&operand_values), "length" => prefix_operator_length( &operand_values ), "index" => prefix_operator_index( &operand_values ), "substr" => prefix_operator_substr( &operand_values ), @@ -331,6 +333,23 @@ fn infix_operator_two_ints_or_two_strings( fi: FI, fs: FS, values: &Vec< } } +fn infix_operator_or( values: &Vec ) -> Result { + 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 ) -> Result { + 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 ) -> Result { assert!( values.len() == 1 ); Ok( values[0].len().to_string() ) @@ -383,4 +402,12 @@ fn prefix_operator_substr( values: &Vec ) -> Result { 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 value_as_bool( s: &str ) -> bool { + if s.len() == 0 { + return false + } + match s.parse::() { + Ok(n) => n != 0, + Err(_) => true, + } +} diff --git a/tests/expr.rs b/tests/expr.rs new file mode 100644 index 000000000..72d07c499 --- /dev/null +++ b/tests/expr.rs @@ -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"); +}