Решение на Логически изрази от Василен Петков

Обратно към всички решения

Към профила на Василен Петков

Резултати

  • 3 точки от тестове
  • 0 бонус точки
  • 3 точки общо
  • 3 успешни тест(а)
  • 17 неуспешни тест(а)

Код

#[derive(Debug, PartialEq, Eq)]
pub enum ParseError {
UnexpectedExpr,
UnexpectedUnaryOp,
UnexpectedBinOp,
UnexpectedParen,
UnexpectedEnd,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum Expr {
Atom(char),
Not(Box<Expr>),
And(Vec<Expr>),
Or(Vec<Expr>),
}
/// Парсър за прост израз, който не съдържа скоби
pub struct SimpleExprParser {
stack: Vec<Expr>,
}
impl SimpleExprParser {
pub fn new() -> SimpleExprParser {
SimpleExprParser { stack: vec![] }
}
/// Приема атом.
pub fn push_atom(&mut self, c: char) -> Result<(), ParseError> {
if let Some(last) = self.stack.last() {
match last {
Expr::And(_) | Expr::Or(_) => return Err(ParseError::UnexpectedExpr),
_ => {}
}
}
self.stack.push(Expr::Atom(c));
Ok(())
}
/// Приема символ за операция.
pub fn push_op(&mut self, op: char) -> Result<(), ParseError> {
if let Some(last) = self.stack.last() {
match last {
Expr::And(_) | Expr::Or(_) => match op {
'&' | '|' => return Err(ParseError::UnexpectedBinOp),
'!' => return Err(ParseError::UnexpectedUnaryOp),
_ => unreachable!(),
},
_ => {}
}
} else if op == '!' {
return Err(ParseError::UnexpectedUnaryOp);
}
match op {
'&' => {
let ands = self.stack.drain(..).collect::<Vec<_>>();
self.stack.push(Expr::And(ands));
}
'|' => {
let ors = self.stack.drain(..).collect::<Vec<_>>();
self.stack.push(Expr::Or(ors));
}
'!' => {
let last = self.stack.pop().ok_or(ParseError::UnexpectedUnaryOp)?;
self.stack.push(Expr::Not(Box::new(last)));
}
_ => unreachable!(),
}
Ok(())
}
/// Завършва парсването и връща построения израз.
pub fn finish(self) -> Result<Expr, ParseError> {
if self.stack.len() != 1 {
Err(ParseError::UnexpectedEnd)
} else {
Ok(self.stack.into_iter().next().unwrap())
}
}
}
/// Парсър за пълния израз
pub struct ExprParser {
stack: Vec<Expr>,
parens: i32,
}
impl ExprParser {
pub fn new() -> ExprParser {
ExprParser { stack: vec![], parens: 0 }
}
/// Приема атом.
pub fn push_atom(&mut self, c: char) -> Result<(), ParseError> {
if let Some(last) = self.stack.last() {
match last {
Expr::And(_) | Expr::Or(_) => return Err(ParseError::UnexpectedExpr),
_ => {}
}
}
self.stack.push(Expr::Atom(c));
Ok(())
}
/// Приема символ за операция.
pub fn push_op(&mut self, op: char) -> Result<(), ParseError> {
if let Some(last) = self.stack.last() {
match last {
Expr::And(_) | Expr::Or(_) => match op {
'&' | '|' => return Err(ParseError::UnexpectedBinOp),
'!' => return Err(ParseError::UnexpectedUnaryOp),
_ => unreachable!(),
},
_ => {}
}
} else if op == '!' {
return Err(ParseError::UnexpectedUnaryOp);
}
match op {
'&' => {
let ands = self.stack.drain(..).collect::<Vec<_>>();
self.stack.push(Expr::And(ands));
}
'|' => {
let ors = self.stack.drain(..).collect::<Vec<_>>();
self.stack.push(Expr::Or(ors));
}
'!' => {
let last = self.stack.pop().ok_or(ParseError::UnexpectedUnaryOp)?;
self.stack.push(Expr::Not(Box::new(last)));
}
_ => unreachable!(),
}
Ok(())
}
/// Завършва парсването и връща построения израз.
pub fn finish(self) -> Result<Expr, ParseError> {
if self.parens > 0 {
Err(ParseError::UnexpectedParen)
} else if self.stack.len() != 1 {
Err(ParseError::UnexpectedEnd)
} else {
Ok(self.stack.into_iter().next().unwrap())
}
}
pub fn open_paren(&mut self) -> Result<(), ParseError> {
self.stack.push(Expr::Atom('(')); // Use a marker
Ok(())
}
pub fn close_paren(&mut self) -> Result<(), ParseError> {
let mut sub_exprs = vec![];
while let Some(expr) = self.stack.pop() {
if let Expr::Atom('(') = expr {
break; // Stop at the matching opening parenthesis
}
sub_exprs.push(expr);
}
sub_exprs.reverse();
self.stack.push(Expr::And(sub_exprs)); // Combine the sub-expression
Ok(())
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum Value {
True,
False,
Expr(Expr),
}
pub fn eval(expr: &Expr, truthy: &[char], falsy: &[char]) -> Value {
match expr {
Expr::Atom(c) => {
if truthy.contains(c) {
Value::True
} else if falsy.contains(c) {
Value::False
} else {
Value::Expr(expr.clone())
}
}
Expr::Not(e) => {
let inner = eval(e, truthy, falsy);
match inner {
Value::True => Value::False,
Value::False => Value::True,
Value::Expr(inner_expr) => Value::Expr(Expr::Not(Box::new(inner_expr))),
}
}
Expr::And(es) => {
for e in es {
let value = eval(e, truthy, falsy);
if value == Value::False {
return Value::False; // Return immediately if any operand is false
}
}
Value::True // Only return true if all operands are true
}
Expr::Or(es) => {
for e in es {
let value = eval(e, truthy, falsy);
if value == Value::True {
return Value::True; // Return immediately if any operand is true
}
}
Value::False // Only return false if all operands are false
}
}
}

Лог от изпълнението

Compiling solution v0.1.0 (/tmp/d20241224-258381-vnfau1/solution)
warning: variable does not need to be mutable
   --> tests/solution_test.rs:306:13
    |
306 |         let mut parser = SimpleExprParser::new();
    |             ----^^^^^^
    |             |
    |             help: remove this `mut`
    |
    = note: `#[warn(unused_mut)]` on by default

warning: `solution` (test "solution_test") generated 1 warning
    Finished test [unoptimized + debuginfo] target(s) in 1.92s
     Running tests/solution_test.rs (target/debug/deps/solution_test-1428e1090729d165)

running 20 tests
test solution_test::test_eval_full ... ok
test solution_test::test_error_paren_mismatched ... FAILED
test solution_test::test_eval_not_and_or ... ok
test solution_test::test_eval_partial ... FAILED
test solution_test::test_eval_unwrap_and_or ... FAILED
test solution_test::test_eval_unwrap_nested ... FAILED
test solution_test::test_paren_around_expr ... FAILED
test solution_test::test_paren_expr_priority ... FAILED
test solution_test::test_paren_not ... FAILED
test solution_test::test_paren_nested ... FAILED
test solution_test::test_parser_alternating_ops ... FAILED
test solution_test::test_paren_surrounded ... FAILED
test solution_test::test_parser_atom ... ok
test solution_test::test_parser_and_or ... FAILED
test solution_test::test_parser_errors_basic ... FAILED
test solution_test::test_parser_error_unexpected_end ... FAILED
test solution_test::test_parser_expr_and_not ... FAILED
test solution_test::test_parser_multiple_atoms_same_op ... FAILED
test solution_test::test_parser_multiple_not ... FAILED
test solution_test::test_parser_not ... FAILED

failures:

---- solution_test::test_error_paren_mismatched stdout ----
thread '<unnamed>' panicked at 'assertion failed: matches!(parser.close_paren(), Err(_))', tests/solution_test.rs:327:9
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
thread 'solution_test::test_error_paren_mismatched' panicked at 'called `Option::unwrap()` on a `None` value', tests/solution_test.rs:325:5

---- solution_test::test_eval_partial stdout ----
thread '<unnamed>' panicked at 'assertion failed: `(left == right)`
  left: `True`,
 right: `Expr(And([Atom('A'), Atom('C')]))`', tests/solution_test.rs:416:9
thread 'solution_test::test_eval_partial' panicked at 'assertion failed: `(left == right)`
  left: `True`,
 right: `Expr(And([Atom('A'), Atom('C')]))`', tests/solution_test.rs:409:5

---- solution_test::test_eval_unwrap_and_or stdout ----
thread '<unnamed>' panicked at 'assertion failed: `(left == right)`
  left: `True`,
 right: `Expr(Atom('B'))`', tests/solution_test.rs:457:9
thread 'solution_test::test_eval_unwrap_and_or' panicked at 'assertion failed: `(left == right)`
  left: `True`,
 right: `Expr(Atom('B'))`', tests/solution_test.rs:456:5

---- solution_test::test_eval_unwrap_nested stdout ----
thread '<unnamed>' panicked at 'assertion failed: `(left == right)`
  left: `True`,
 right: `Expr(Or([Atom('X'), Atom('B'), Not(Atom('D')), Atom('Y')]))`', tests/solution_test.rs:480:9
thread 'solution_test::test_eval_unwrap_nested' panicked at 'assertion failed: `(left == right)`
  left: `True`,
 right: `Expr(Or([Atom('X'), Atom('B'), Not(Atom('D')), Atom('Y')]))`', tests/solution_test.rs:479:5

---- solution_test::test_paren_around_expr stdout ----
thread '<unnamed>' panicked at 'assertion failed: `(left == right)`
  left: `And([Atom('A')])`,
 right: `Atom('A')`', tests/solution_test.rs:179:9
thread 'solution_test::test_paren_around_expr' panicked at 'assertion failed: `(left == right)`
  left: `And([Atom('A')])`,
 right: `Atom('A')`', tests/solution_test.rs:176:5

---- solution_test::test_paren_expr_priority stdout ----
thread '<unnamed>' panicked at 'called `Result::unwrap()` on an `Err` value: UnexpectedExpr', tests/solution_test.rs:199:47
thread 'solution_test::test_paren_expr_priority' panicked at 'called `Result::unwrap()` on an `Err` value: UnexpectedExpr', tests/solution_test.rs:197:5

---- solution_test::test_paren_not stdout ----
thread '<unnamed>' panicked at 'called `Result::unwrap()` on an `Err` value: UnexpectedUnaryOp', tests/solution_test.rs:218:48
thread 'solution_test::test_paren_not' panicked at 'called `Result::unwrap()` on an `Err` value: UnexpectedUnaryOp', tests/solution_test.rs:216:5

---- solution_test::test_paren_nested stdout ----
thread '<unnamed>' panicked at 'called `Result::unwrap()` on an `Err` value: UnexpectedUnaryOp', tests/solution_test.rs:254:58
thread 'solution_test::test_paren_nested' panicked at 'called `Result::unwrap()` on an `Err` value: UnexpectedUnaryOp', tests/solution_test.rs:252:5

---- solution_test::test_parser_alternating_ops stdout ----
thread '<unnamed>' panicked at 'called `Result::unwrap()` on an `Err` value: UnexpectedExpr', tests/solution_test.rs:159:51
thread 'solution_test::test_parser_alternating_ops' panicked at 'called `Result::unwrap()` on an `Err` value: UnexpectedExpr', tests/solution_test.rs:157:5

---- solution_test::test_paren_surrounded stdout ----
thread '<unnamed>' panicked at 'called `Result::unwrap()` on an `Err` value: UnexpectedExpr', tests/solution_test.rs:237:61
thread 'solution_test::test_paren_surrounded' panicked at 'called `Result::unwrap()` on an `Err` value: UnexpectedExpr', tests/solution_test.rs:235:5

---- solution_test::test_parser_and_or stdout ----
thread '<unnamed>' panicked at 'called `Result::unwrap()` on an `Err` value: UnexpectedExpr', tests/solution_test.rs:87:43
thread 'solution_test::test_parser_and_or' panicked at 'called `Result::unwrap()` on an `Err` value: UnexpectedExpr', tests/solution_test.rs:84:5

---- solution_test::test_parser_errors_basic stdout ----
thread '<unnamed>' panicked at 'assertion failed: matches!(parser.push_op(\'&\'), Err(_))', tests/solution_test.rs:267:9
thread 'solution_test::test_parser_errors_basic' panicked at 'called `Option::unwrap()` on a `None` value', tests/solution_test.rs:265:5

---- solution_test::test_parser_error_unexpected_end stdout ----
thread '<unnamed>' panicked at 'assertion failed: matches!(parser.finish(), Err(_))', tests/solution_test.rs:311:9
thread 'solution_test::test_parser_error_unexpected_end' panicked at 'called `Option::unwrap()` on a `None` value', tests/solution_test.rs:305:5

---- solution_test::test_parser_expr_and_not stdout ----
thread '<unnamed>' panicked at 'called `Result::unwrap()` on an `Err` value: UnexpectedUnaryOp', tests/solution_test.rs:109:44
thread 'solution_test::test_parser_expr_and_not' panicked at 'called `Result::unwrap()` on an `Err` value: UnexpectedUnaryOp', tests/solution_test.rs:107:5

---- solution_test::test_parser_multiple_atoms_same_op stdout ----
thread '<unnamed>' panicked at 'called `Result::unwrap()` on an `Err` value: UnexpectedExpr', tests/solution_test.rs:126:47
thread 'solution_test::test_parser_multiple_atoms_same_op' panicked at 'called `Result::unwrap()` on an `Err` value: UnexpectedExpr', tests/solution_test.rs:124:5

---- solution_test::test_parser_multiple_not stdout ----
thread '<unnamed>' panicked at 'called `Result::unwrap()` on an `Err` value: UnexpectedUnaryOp', tests/solution_test.rs:142:42
thread 'solution_test::test_parser_multiple_not' panicked at 'called `Result::unwrap()` on an `Err` value: UnexpectedUnaryOp', tests/solution_test.rs:140:5

---- solution_test::test_parser_not stdout ----
thread '<unnamed>' panicked at 'called `Result::unwrap()` on an `Err` value: UnexpectedUnaryOp', tests/solution_test.rs:100:40
thread 'solution_test::test_parser_not' panicked at 'called `Result::unwrap()` on an `Err` value: UnexpectedUnaryOp', tests/solution_test.rs:98:5


failures:
    solution_test::test_error_paren_mismatched
    solution_test::test_eval_partial
    solution_test::test_eval_unwrap_and_or
    solution_test::test_eval_unwrap_nested
    solution_test::test_paren_around_expr
    solution_test::test_paren_expr_priority
    solution_test::test_paren_nested
    solution_test::test_paren_not
    solution_test::test_paren_surrounded
    solution_test::test_parser_alternating_ops
    solution_test::test_parser_and_or
    solution_test::test_parser_error_unexpected_end
    solution_test::test_parser_errors_basic
    solution_test::test_parser_expr_and_not
    solution_test::test_parser_multiple_atoms_same_op
    solution_test::test_parser_multiple_not
    solution_test::test_parser_not

test result: FAILED. 3 passed; 17 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

error: test failed, to rerun pass `--test solution_test`

История (2 версии и 1 коментар)

Василен качи първо решение на 18.12.2024 00:12 (преди 9 месеца)

Имаш някакъв фундаментален пропуск в решението и не изкарваш почти никакви точки. Имаш тестове, но те са написани по такъв начин, че явно не хващат проблема. Погледни си решението отново и тествай стъпка по стъпка.
Също така в теста test_simple_and имаш грешен очакван резултат.

Василен качи решение на 22.12.2024 18:00 (преди 9 месеца)

-
#[derive(Debug, PartialEq, Eq)]
pub enum ParseError {
UnexpectedExpr,
UnexpectedUnaryOp,
UnexpectedBinOp,
UnexpectedParen,
UnexpectedEnd,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum Expr {
Atom(char),
Not(Box<Expr>),
And(Vec<Expr>),
Or(Vec<Expr>),
}
/// Парсър за прост израз, който не съдържа скоби
pub struct SimpleExprParser {
stack: Vec<Expr>,
}
impl SimpleExprParser {
pub fn new() -> SimpleExprParser {
SimpleExprParser { stack: vec![] }
}
/// Приема атом.
pub fn push_atom(&mut self, c: char) -> Result<(), ParseError> {
if let Some(last) = self.stack.last() {
match last {
Expr::And(_) | Expr::Or(_) => return Err(ParseError::UnexpectedExpr),
_ => {}
}
}
self.stack.push(Expr::Atom(c));
Ok(())
}
/// Приема символ за операция.
pub fn push_op(&mut self, op: char) -> Result<(), ParseError> {
if let Some(last) = self.stack.last() {
match last {
Expr::And(_) | Expr::Or(_) => match op {
'&' | '|' => return Err(ParseError::UnexpectedBinOp),
'!' => return Err(ParseError::UnexpectedUnaryOp),
_ => unreachable!(),
},
_ => {}
}
} else if op == '!' {
return Err(ParseError::UnexpectedUnaryOp);
}
match op {
'&' => {
let ands = self.stack.drain(..).collect::<Vec<_>>();
self.stack.push(Expr::And(ands));
}
'|' => {
let ors = self.stack.drain(..).collect::<Vec<_>>();
self.stack.push(Expr::Or(ors));
}
'!' => {
let last = self.stack.pop().ok_or(ParseError::UnexpectedUnaryOp)?;
self.stack.push(Expr::Not(Box::new(last)));
}
_ => unreachable!(),
}
Ok(())
}
/// Завършва парсването и връща построения израз.
pub fn finish(self) -> Result<Expr, ParseError> {
if self.stack.len() != 1 {
Err(ParseError::UnexpectedEnd)
} else {
Ok(self.stack.into_iter().next().unwrap())
}
}
-}
+
+ }
+
+
+
/// Парсър за пълния израз
pub struct ExprParser {
stack: Vec<Expr>,
parens: i32,
}
impl ExprParser {
pub fn new() -> ExprParser {
ExprParser { stack: vec![], parens: 0 }
}
/// Приема атом.
pub fn push_atom(&mut self, c: char) -> Result<(), ParseError> {
if let Some(last) = self.stack.last() {
match last {
Expr::And(_) | Expr::Or(_) => return Err(ParseError::UnexpectedExpr),
_ => {}
}
}
self.stack.push(Expr::Atom(c));
Ok(())
}
/// Приема символ за операция.
pub fn push_op(&mut self, op: char) -> Result<(), ParseError> {
if let Some(last) = self.stack.last() {
match last {
Expr::And(_) | Expr::Or(_) => match op {
'&' | '|' => return Err(ParseError::UnexpectedBinOp),
'!' => return Err(ParseError::UnexpectedUnaryOp),
_ => unreachable!(),
},
_ => {}
}
} else if op == '!' {
return Err(ParseError::UnexpectedUnaryOp);
}
match op {
'&' => {
let ands = self.stack.drain(..).collect::<Vec<_>>();
self.stack.push(Expr::And(ands));
}
'|' => {
let ors = self.stack.drain(..).collect::<Vec<_>>();
self.stack.push(Expr::Or(ors));
}
'!' => {
let last = self.stack.pop().ok_or(ParseError::UnexpectedUnaryOp)?;
self.stack.push(Expr::Not(Box::new(last)));
}
_ => unreachable!(),
}
Ok(())
}
- /// Приема отваряща скоба.
- pub fn open_paren(&mut self) -> Result<(), ParseError> {
- self.parens += 1;
- Ok(())
- }
+
- /// Приема затваряща скоба.
- pub fn close_paren(&mut self) -> Result<(), ParseError> {
- if self.parens == 0 {
- return Err(ParseError::UnexpectedParen);
- }
- self.parens -= 1;
- Ok(())
- }
-
/// Завършва парсването и връща построения израз.
pub fn finish(self) -> Result<Expr, ParseError> {
if self.parens > 0 {
Err(ParseError::UnexpectedParen)
} else if self.stack.len() != 1 {
Err(ParseError::UnexpectedEnd)
} else {
Ok(self.stack.into_iter().next().unwrap())
}
}
+
+
+ pub fn open_paren(&mut self) -> Result<(), ParseError> {
+ self.stack.push(Expr::Atom('(')); // Use a marker
+ Ok(())
+ }
+
+ pub fn close_paren(&mut self) -> Result<(), ParseError> {
+ let mut sub_exprs = vec![];
+ while let Some(expr) = self.stack.pop() {
+ if let Expr::Atom('(') = expr {
+ break; // Stop at the matching opening parenthesis
+ }
+ sub_exprs.push(expr);
+ }
+ sub_exprs.reverse();
+ self.stack.push(Expr::And(sub_exprs)); // Combine the sub-expression
+ Ok(())
+ }
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum Value {
True,
False,
Expr(Expr),
}
pub fn eval(expr: &Expr, truthy: &[char], falsy: &[char]) -> Value {
match expr {
Expr::Atom(c) => {
if truthy.contains(c) {
Value::True
} else if falsy.contains(c) {
Value::False
} else {
Value::Expr(expr.clone())
}
}
Expr::Not(e) => {
let inner = eval(e, truthy, falsy);
match inner {
Value::True => Value::False,
Value::False => Value::True,
Value::Expr(inner_expr) => Value::Expr(Expr::Not(Box::new(inner_expr))),
}
}
Expr::And(es) => {
for e in es {
let value = eval(e, truthy, falsy);
if value == Value::False {
return Value::False; // Return immediately if any operand is false
}
}
Value::True // Only return true if all operands are true
}
Expr::Or(es) => {
for e in es {
let value = eval(e, truthy, falsy);
if value == Value::True {
return Value::True; // Return immediately if any operand is true
}
}
Value::False // Only return false if all operands are false
}
}
}
-
-
-#[test]
-fn test_basic_simple_parser() {
- // A & B
- let mut simple_parser = SimpleExprParser::new();
- let _ = simple_parser.push_atom('A');
- let _ = simple_parser.push_op('&');
- let _ = simple_parser.push_atom('B');
- let expr = simple_parser.finish().unwrap();
-
- eval(&expr, &['A'], &['B']);
-}
-
-#[test]
-fn test_basic_expr_parser() {
- // A & (B | !C)
- let mut full_parser = ExprParser::new();
- let _ = full_parser.push_atom('A');
- let _ = full_parser.push_op('&');
- let _ = full_parser.open_paren();
- let _ = full_parser.push_atom('B');
- let _ = full_parser.push_op('|');
- let _ = full_parser.push_op('!');
- let _ = full_parser.push_atom('C');
- let _ = full_parser.close_paren();
- let expr = full_parser.finish().unwrap();
-
- eval(&expr, &['A'], &['B']);
-}
-
-#[test]
-fn test_basic_errors() {
- let mut simple_parser = SimpleExprParser::new();
- let _ = simple_parser.push_atom('A');
- let _ = simple_parser.push_op('&');
- assert_eq!(simple_parser.push_op('&'), Err(ParseError::UnexpectedBinOp));
-
- let mut simple_parser = SimpleExprParser::new();
- let _ = simple_parser.push_atom('A');
- let _ = simple_parser.push_op('&');
- let _ = simple_parser.push_atom('B');
- assert_eq!(simple_parser.push_atom('B'), Err(ParseError::UnexpectedExpr));
-}
-
-#[test]
-fn test_simple_and() {
- // A & B & C
- let mut simple_parser = SimpleExprParser::new();
- let _ = simple_parser.push_atom('A');
- let _ = simple_parser.push_op('&');
- let _ = simple_parser.push_atom('B');
- let _ = simple_parser.push_op('&');
- let _ = simple_parser.push_atom('C');
- let expr = simple_parser.finish().unwrap();
-
- assert_eq!(eval(&expr, &['A', 'B'], &['C']), Value::True);
-}
-
-#[test]
-fn test_simple_or() {
- // A | B | C
- let mut simple_parser = SimpleExprParser::new();
- let _ = simple_parser.push_atom('A');
- let _ = simple_parser.push_op('|');
- let _ = simple_parser.push_atom('B');
- let _ = simple_parser.push_op('|');
- let _ = simple_parser.push_atom('C');
- let expr = simple_parser.finish().unwrap();
-
- assert_eq!(eval(&expr, &['A', 'B'], &['C']), Value::True);
-}
-
-#[test]
-fn test_simple_not() {
- // !A & !B
- let mut simple_parser = SimpleExprParser::new();
- let _ = simple_parser.push_op('!');
- let _ = simple_parser.push_atom('A');
- let _ = simple_parser.push_op('&');
- let _ = simple_parser.push_op('!');
- let _ = simple_parser.push_atom('B');
- let expr = simple_parser.finish().unwrap();
-
- assert_eq!(eval(&expr, &['A', 'B'], &[]), Value::True);
-}
-
-#[test]
-fn test_simple_mixed() {
- // A & !B | C
- let mut simple_parser = SimpleExprParser::new();
- let _ = simple_parser.push_atom('A');
- let _ = simple_parser.push_op('&');
- let _ = simple_parser.push_op('!');
- let _ = simple_parser.push_atom('B');
- let _ = simple_parser.push_op('|');
- let _ = simple_parser.push_atom('C');
- let expr = simple_parser.finish().unwrap();
-
- assert_eq!(eval(&expr, &['A', 'B'], &['C']), Value::True);
-}
-
-#[test]
-fn test_expr_with_parens() {
- // (A & B) | C
- let mut full_parser = ExprParser::new();
- let _ = full_parser.open_paren();
- let _ = full_parser.push_atom('A');
- let _ = full_parser.push_op('&');
- let _ = full_parser.push_atom('B');
- let _ = full_parser.close_paren();
- let _ = full_parser.push_op('|');
- let _ = full_parser.push_atom('C');
- let expr = full_parser.finish().unwrap();
-
- assert_eq!(eval(&expr, &['A', 'B'], &['C']), Value::True);
-}
-
-#[test]
-fn test_nested_parens() {
- // ((A & B) | C) & D
- let mut full_parser = ExprParser::new();
- let _ = full_parser.open_paren();
- let _ = full_parser.open_paren();
- let _ = full_parser.push_atom('A');
- let _ = full_parser.push_op('&');
- let _ = full_parser.push_atom('B');
- let _ = full_parser.close_paren();
- let _ = full_parser.push_op('|');
- let _ = full_parser.push_atom('C');
- let _ = full_parser.close_paren();
- let _ = full_parser.push_op('&');
- let _ = full_parser.push_atom('D');
- let expr = full_parser.finish().unwrap();
-
- assert_eq!(eval(&expr, &['A', 'B', 'D'], &['C']), Value::True);
-}
-
-#[test]
-fn test_complex_expression() {
- // !(A & B) | (C & !D)
- let mut full_parser = ExprParser::new();
- let _ = full_parser.push_op('!');
- let _ = full_parser.open_paren();
- let _ = full_parser.push_atom('A');
- let _ = full_parser.push_op('&');
- let _ = full_parser.push_atom('B');
- let _ = full_parser.close_paren();
- let _ = full_parser.push_op('|');
- let _ = full_parser.open_paren();
- let _ = full_parser.push_atom('C');
- let _ = full_parser.push_op('&');
- let _ = full_parser.push_op('!');
- let _ = full_parser.push_atom('D');
- let _ = full_parser.close_paren();
- let expr = full_parser.finish().unwrap();
-
- assert_eq!(eval(&expr, &['A', 'B', 'C'], &['D']), Value::True);
-}
-
-macro_rules! expr {
- (atom($c:expr)) => {
- Expr::Atom($c)
- };
- (not($e:expr)) => {
- Expr::Not(Box::new($e))
- };
- (and($($e:expr),*)) => {
- Expr::And(vec![$($e),*])
- };
- (or($($e:expr),*)) => {
- Expr::Or(vec![$($e),*])
- };
-}