Решение на Логически изрази от Пламен Дарджиков
Към профила на Пламен Дарджиков
Резултати
- 19 точки от тестове
- 0 бонус точки
- 19 точки общо
- 19 успешни тест(а)
- 1 неуспешни тест(а)
Код
use std::collections::VecDeque;
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum Expr {
Atom(char),
Not(Box<Expr>),
And(Vec<Expr>),
Or(Vec<Expr>),
}
#[derive(Debug, PartialEq, Eq)]
pub enum ParseError {
UnexpectedExpr,
UnexpectedUnaryOp,
UnexpectedBinOp,
UnexpectedParen,
UnexpectedEnd,
}
pub struct SimpleExprParser {
expressionVector: VecDeque<Expr>,
operatorVector: VecDeque<char>,
lastCharIsAtom: bool,
lastWasNegative: bool,
}
impl SimpleExprParser {
pub fn new() -> SimpleExprParser {
SimpleExprParser {expressionVector: VecDeque::new(), operatorVector: VecDeque::new(), lastCharIsAtom: false, lastWasNegative: false}
}
pub fn push_atom(&mut self, c: char) -> Result<(), ParseError> {
if self.lastCharIsAtom {
return Err(ParseError::UnexpectedExpr);
}
self.expressionVector.push_back(if self.lastWasNegative {
Expr::Not(Box::new(Expr::Atom(c)))
} else {
Expr::Atom(c)
});
self.lastCharIsAtom = true;
self.lastWasNegative = false;
Ok(())
}
pub fn push_op(&mut self, op: char) -> Result<(), ParseError> {
match op {
'&' | '|' => {
if !self.lastCharIsAtom {
return Err(ParseError::UnexpectedBinOp);
}
self.lastWasNegative = false;
}
'!' | _ => {
if self.lastCharIsAtom {
return Err(ParseError::UnexpectedUnaryOp);
}
self.lastWasNegative = true;
}
}
self.operatorVector.push_back(op);
self.lastCharIsAtom = false;
Ok(())
}
pub fn finish(self) -> Result<Expr, ParseError> {
let mut parser = self;
if !parser.lastCharIsAtom {
return Err(ParseError::UnexpectedEnd);
}
while let Some(op) = parser.operatorVector.pop_front() {
match op {
'&' | '|' => {
let mut groupedExpression: Vec::<Expr> = vec![parser.expressionVector.pop_front().unwrap()];
while let Some(expression) = parser.expressionVector.pop_front() {
groupedExpression.push(expression);
if parser.operatorVector.front().cloned() != Some(op) {
break;
}
parser.operatorVector.pop_front();
}
parser.expressionVector.push_front(match op {
'&' => Expr::And(groupedExpression),
_ => Expr::Or(groupedExpression),
});
}
_ => {}
}
}
if let Some(expr) = parser.expressionVector.pop_front() {
if !parser.expressionVector.is_empty() {
return Err(ParseError::UnexpectedExpr);
}
Ok(expr)
} else {
return Err(ParseError::UnexpectedExpr);
}
}
}
pub struct ExprParser {
expressionVector: VecDeque<Expr>,
operatorVector: VecDeque<char>,
lastCharIsAtom: bool,
beforeParenExpr: Vec<VecDeque<Expr>>,
beforeParenOp: Vec<VecDeque<char>>,
lastWasNegative: bool,
}
impl ExprParser {
pub fn new() -> ExprParser {
ExprParser {expressionVector: VecDeque::new(), operatorVector: VecDeque::new(), lastCharIsAtom: false, beforeParenExpr: Vec::new(), beforeParenOp: Vec::new(), lastWasNegative: false}
}
pub fn push_atom(&mut self, c: char) -> Result<(), ParseError> {
if self.lastCharIsAtom {
return Err(ParseError::UnexpectedExpr);
}
self.expressionVector.push_back(if self.lastWasNegative {
self.operatorVector.pop_back();
Expr::Not(Box::new(Expr::Atom(c)))
} else {
Expr::Atom(c)
});
self.lastCharIsAtom = true;
self.lastWasNegative = false;
Ok(())
}
pub fn push_op(&mut self, op: char) -> Result<(), ParseError> {
match op {
'&' | '|' => {
if !self.lastCharIsAtom {
return Err(ParseError::UnexpectedBinOp);
}
self.lastWasNegative = false;
}
'!' | _ => {
if self.lastCharIsAtom {
return Err(ParseError::UnexpectedUnaryOp);
}
self.lastWasNegative = true;
}
}
self.operatorVector.push_back(op);
self.lastCharIsAtom = false;
Ok(())
}
pub fn open_paren(&mut self) -> Result<(), ParseError> {
if self.lastCharIsAtom {
return Err(ParseError::UnexpectedParen);
}
self.beforeParenExpr.push(self.expressionVector.clone());
self.beforeParenOp.push(self.operatorVector.clone());
self.lastWasNegative = false;
self.operatorVector.push_back('(');
self.expressionVector.clear();
self.operatorVector.clear();
Ok(())
}
pub fn close_paren(&mut self) -> Result<(), ParseError> {
if !self.lastCharIsAtom || self.beforeParenExpr.is_empty() {
return Err(ParseError::UnexpectedParen);
}
while let Some(op) = self.operatorVector.pop_front() {
if op == '(' {
break;
}
let res = self.use_operator(op);
if res.is_err() {
return Err(res.unwrap_err());
}
}
if let Some(prev_expr) = self.beforeParenExpr.pop() {
for expr in prev_expr.into_iter().rev() {
self.expressionVector.push_front(expr);
}
}
self.operatorVector = self.beforeParenOp.pop().unwrap();
if let Some(op) = self.operatorVector.back() {
if op.clone() == '!' {
let exprToNegate = self.expressionVector.pop_back().unwrap();
self.expressionVector.push_back(Expr::Not(Box::new(exprToNegate)));
self.operatorVector.pop_back();
}
}
Ok(())
}
pub fn finish(self) -> Result<Expr, ParseError> {
let mut parser = self;
if !parser.lastCharIsAtom {
return Err(ParseError::UnexpectedEnd);
}
if !parser.beforeParenExpr.is_empty() {
return Err(ParseError::UnexpectedParen);
}
while let Some(op) = parser.operatorVector.pop_front() {
let res = parser.use_operator(op);
if res.is_err() {
return Err(res.unwrap_err());
}
}
if let Some(expr) = parser.expressionVector.pop_front() {
if !parser.expressionVector.is_empty() {
return Err(ParseError::UnexpectedBinOp);
}
Ok(expr)
} else {
return Err(ParseError::UnexpectedExpr);
}
}
fn use_operator(&mut self, op: char) -> Result<(), ParseError> {
match op {
'&' | '|' => {
let mut groupedExpression: Vec<Expr> = vec![self.expressionVector.pop_front().unwrap()];
while let Some(expression) = self.expressionVector.pop_front() {
groupedExpression.push(expression);
if self.operatorVector.front().cloned() != Some(op) {
break;
}
self.operatorVector.pop_front();
}
self.expressionVector.push_front(match op {
'&' => Expr::And(groupedExpression),
_ => Expr::Or(groupedExpression),
});
}
_ => {}
}
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()) // If the value is unknown, return the expression itself
}
}
Expr::Not(innerExpr) => {
match eval(innerExpr, truthy, falsy) {
Value::True => Value::False,
Value::False => Value::True,
Value::Expr(e) => {
match e {
Expr::Not(otherE) => {
Value::Expr(*otherE)
}
_ => {
Value::Expr(Expr::Not(Box::new(e)))
}
}
},
}
}
Expr::And(expressions) => {
let mut simplifiedExprs: Vec<Expr> = Vec::new();
let mut hasFalse = false;
for expr in expressions {
match eval(expr, truthy, falsy) {
Value::False => hasFalse = true,
Value::Expr(e) => simplifiedExprs.push(e),
_ => {}
}
}
if hasFalse {
Value::False
} else if simplifiedExprs.is_empty() {
Value::True
} else if simplifiedExprs.len() == 1{
Value::Expr(simplifiedExprs.first().unwrap().clone())
} else {
Value::Expr(Expr::And(simplifiedExprs))
}
}
Expr::Or(expressions) => {
let mut simplifiedExprs: Vec<Expr> = Vec::new();
let mut hasTrue = false;
for expr in expressions {
match eval(expr, truthy, falsy) {
Value::True => hasTrue = true,
Value::Expr(e) => simplifiedExprs.push(e),
_ => {}
}
}
if hasTrue {
Value::True
} else if simplifiedExprs.is_empty() {
Value::False
} else if simplifiedExprs.len() == 1 {
Value::Expr(simplifiedExprs.first().unwrap().clone())
} else {
Value::Expr(Expr::Or(simplifiedExprs))
}
}
}
}
Лог от изпълнението
Compiling solution v0.1.0 (/tmp/d20241224-258381-rbi409/solution) warning: structure field `expressionVector` should have a snake case name --> src/lib.rs:21:5 | 21 | expressionVector: VecDeque<Expr>, | ^^^^^^^^^^^^^^^^ help: convert the identifier to snake case: `expression_vector` | = note: `#[warn(non_snake_case)]` on by default warning: structure field `operatorVector` should have a snake case name --> src/lib.rs:22:5 | 22 | operatorVector: VecDeque<char>, | ^^^^^^^^^^^^^^ help: convert the identifier to snake case: `operator_vector` warning: structure field `lastCharIsAtom` should have a snake case name --> src/lib.rs:23:5 | 23 | lastCharIsAtom: bool, | ^^^^^^^^^^^^^^ help: convert the identifier to snake case: `last_char_is_atom` warning: structure field `lastWasNegative` should have a snake case name --> src/lib.rs:24:5 | 24 | lastWasNegative: bool, | ^^^^^^^^^^^^^^^ help: convert the identifier to snake case: `last_was_negative` warning: variable `groupedExpression` should have a snake case name --> src/lib.rs:78:29 | 78 | let mut groupedExpression: Vec::<Expr> = vec![parser.expressionVector.pop_front().unwrap()]; | ^^^^^^^^^^^^^^^^^ help: convert the identifier to snake case: `grouped_expression` warning: structure field `expressionVector` should have a snake case name --> src/lib.rs:110:5 | 110 | expressionVector: VecDeque<Expr>, | ^^^^^^^^^^^^^^^^ help: convert the identifier to snake case: `expression_vector` warning: structure field `operatorVector` should have a snake case name --> src/lib.rs:111:5 | 111 | operatorVector: VecDeque<char>, | ^^^^^^^^^^^^^^ help: convert the identifier to snake case: `operator_vector` warning: structure field `lastCharIsAtom` should have a snake case name --> src/lib.rs:112:5 | 112 | lastCharIsAtom: bool, | ^^^^^^^^^^^^^^ help: convert the identifier to snake case: `last_char_is_atom` warning: structure field `beforeParenExpr` should have a snake case name --> src/lib.rs:113:5 | 113 | beforeParenExpr: Vec<VecDeque<Expr>>, | ^^^^^^^^^^^^^^^ help: convert the identifier to snake case: `before_paren_expr` warning: structure field `beforeParenOp` should have a snake case name --> src/lib.rs:114:5 | 114 | beforeParenOp: Vec<VecDeque<char>>, | ^^^^^^^^^^^^^ help: convert the identifier to snake case: `before_paren_op` warning: structure field `lastWasNegative` should have a snake case name --> src/lib.rs:115:5 | 115 | lastWasNegative: bool, | ^^^^^^^^^^^^^^^ help: convert the identifier to snake case: `last_was_negative` warning: variable `exprToNegate` should have a snake case name --> src/lib.rs:201:21 | 201 | let exprToNegate = self.expressionVector.pop_back().unwrap(); | ^^^^^^^^^^^^ help: convert the identifier to snake case: `expr_to_negate` warning: variable `groupedExpression` should have a snake case name --> src/lib.rs:244:25 | 244 | let mut groupedExpression: Vec<Expr> = vec![self.expressionVector.pop_front().unwrap()]; | ^^^^^^^^^^^^^^^^^ help: convert the identifier to snake case: `grouped_expression` warning: variable `innerExpr` should have a snake case name --> src/lib.rs:282:19 | 282 | Expr::Not(innerExpr) => { | ^^^^^^^^^ help: convert the identifier to snake case: `inner_expr` warning: variable `otherE` should have a snake case name --> src/lib.rs:288:35 | 288 | Expr::Not(otherE) => { | ^^^^^^ help: convert the identifier to snake case: `other_e` warning: variable `simplifiedExprs` should have a snake case name --> src/lib.rs:299:21 | 299 | let mut simplifiedExprs: Vec<Expr> = Vec::new(); | ^^^^^^^^^^^^^^^ help: convert the identifier to snake case: `simplified_exprs` warning: variable `hasFalse` should have a snake case name --> src/lib.rs:300:21 | 300 | let mut hasFalse = false; | ^^^^^^^^ help: convert the identifier to snake case: `has_false` warning: variable `simplifiedExprs` should have a snake case name --> src/lib.rs:321:21 | 321 | let mut simplifiedExprs: Vec<Expr> = Vec::new(); | ^^^^^^^^^^^^^^^ help: convert the identifier to snake case: `simplified_exprs` warning: variable `hasTrue` should have a snake case name --> src/lib.rs:322:21 | 322 | let mut hasTrue = false; | ^^^^^^^ help: convert the identifier to snake case: `has_true` warning: `solution` (lib) generated 19 warnings 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.83s 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 ... ok test solution_test::test_eval_not_and_or ... ok test solution_test::test_eval_partial ... ok test solution_test::test_eval_unwrap_nested ... ok test solution_test::test_eval_unwrap_and_or ... ok test solution_test::test_paren_around_expr ... ok test solution_test::test_paren_expr_priority ... ok test solution_test::test_paren_nested ... ok test solution_test::test_paren_not ... ok test solution_test::test_paren_surrounded ... ok test solution_test::test_parser_alternating_ops ... ok test solution_test::test_parser_and_or ... ok test solution_test::test_parser_atom ... ok test solution_test::test_parser_error_unexpected_end ... ok test solution_test::test_parser_errors_basic ... ok test solution_test::test_parser_expr_and_not ... ok test solution_test::test_parser_multiple_atoms_same_op ... ok test solution_test::test_parser_not ... ok test solution_test::test_parser_multiple_not ... FAILED failures: ---- solution_test::test_parser_multiple_not stdout ---- thread '<unnamed>' panicked at 'assertion failed: `(left == right)` left: `Not(Atom('B'))`, right: `Not(Not(Not(Atom('B'))))`', tests/solution_test.rs:143:9 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace thread 'solution_test::test_parser_multiple_not' panicked at 'assertion failed: `(left == right)` left: `Not(Atom('B'))`, right: `Not(Not(Not(Atom('B'))))`', tests/solution_test.rs:140:5 failures: solution_test::test_parser_multiple_not test result: FAILED. 19 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s error: test failed, to rerun pass `--test solution_test`