Решение на Логически изрази от Йоанна Ненкова

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

Към профила на Йоанна Ненкова

Резултати

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

Код

#[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 {
current_expr: Option<Expr>,
current_op: Option<char>,
}
impl SimpleExprParser {
pub fn new() -> SimpleExprParser {
SimpleExprParser {
current_expr: None,
current_op: None,
}
}
pub fn push_atom(&mut self, c: char) -> Result<(), ParseError> {
if self.current_op == Some('!') {
self.current_expr = Some(Expr::Not(Box::new(Expr::Atom(c))));
self.current_op = None;
} else if let Some(op) = self.current_op {
let new_expr = Expr::Atom(c);
self.current_expr = match op {
'&' => self.combine(&Expr::And, new_expr),
'|' => self.combine(&Expr::Or, new_expr),
_ => return Err(ParseError::UnexpectedBinOp),
};
self.current_op = None;
} else if self.current_expr.is_some() {
return Err(ParseError::UnexpectedExpr);
} else {
self.current_expr = Some(Expr::Atom(c));
}
Ok(())
}
pub fn push_op(&mut self, op: char) -> Result<(), ParseError> {
if self.current_op.is_some() {
return Err(ParseError::UnexpectedBinOp);
}
if self.current_expr.is_none() && op != '!' {
return Err(ParseError::UnexpectedExpr);
}
self.current_op = Some(op);
Ok(())
}
pub fn finish(self) -> Result<Expr, ParseError> {
self.current_expr.ok_or(ParseError::UnexpectedEnd)
}
fn combine<F>(&mut self, constructor: &F, new_expr: Expr) -> Option<Expr>
where
F: FnOnce(Vec<Expr>) -> Expr + Clone,
{
match self.current_expr.take() {
Some(Expr::And(mut vec)) if std::mem::discriminant(&constructor.clone()(vec![])) == std::mem::discriminant(&Expr::And(vec![]))
=> {
vec.push(new_expr);
Some(Expr::And(vec))
}
Some(Expr::Or(mut vec)) if std::mem::discriminant(&constructor.clone()(vec![])) == std::mem::discriminant(&Expr::Or(vec![]))
=> {
vec.push(new_expr);
Some(Expr::Or(vec))
}
Some(expr) => Some(constructor.clone()(vec![expr, new_expr])),
None => None,
}
}
}
pub struct ExprParser {
stack: Vec<(Option<char>, Option<Expr>)>,
}
impl ExprParser {
pub fn new() -> ExprParser {
ExprParser { stack: vec![] }
}
pub fn push_atom(&mut self, c: char) -> Result<(), ParseError> {
self.push_expr(Expr::Atom(c))
}
pub fn push_op(&mut self, op: char) -> Result<(), ParseError> {
if let Some((None, None)) = self.stack.last() {
self.stack.push((Some(op), None));
} else {
return Err(ParseError::UnexpectedUnaryOp);
}
Ok(())
}
pub fn open_paren(&mut self) -> Result<(), ParseError> {
self.stack.push((None, None));
Ok(())
}
pub fn close_paren(&mut self) -> Result<(), ParseError> {
if let Some((_op, expr)) = self.stack.pop() {
if let Some(e) = expr {
self.push_expr(e)?;
} else {
return Err(ParseError::UnexpectedParen);
}
} else {
return Err(ParseError::UnexpectedParen);
}
Ok(())
}
pub fn finish(mut self) -> Result<Expr, ParseError> {
if let Some((_, Some(expr))) = self.stack.pop() {
Ok(expr)
} else {
Err(ParseError::UnexpectedEnd)
}
}
fn push_expr(&mut self, expr: Expr) -> Result<(), ParseError> {
if let Some((op, current_expr)) = self.stack.last_mut() {
match op {
Some('&') => *current_expr = combine(&Expr::And, current_expr.take(), expr),
Some('|') => *current_expr = combine(&Expr::Or, current_expr.take(), expr),
Some('!') => *current_expr = Some(Expr::Not(Box::new(expr))),
_ => *current_expr = Some(expr),
}
} else {
self.stack.push((None, Some(expr)));
}
Ok(())
}
}
fn combine<F>(constructor: &F, current_expr: Option<Expr>, new_expr: Expr) -> Option<Expr>
where
F: FnOnce(Vec<Expr>) -> Expr + Clone,
{
match current_expr {
Some(Expr::And(mut vec)) if std::mem::discriminant(&constructor.clone()(vec![])) == std::mem::discriminant(&Expr::And(vec![]))
=> {
vec.push(new_expr);
Some(Expr::And(vec))
}
Some(Expr::Or(mut vec)) if std::mem::discriminant(&constructor.clone()(vec![])) == std::mem::discriminant(&Expr::Or(vec![]))
=> {
vec.push(new_expr);
Some(Expr::Or(vec))
}
Some(expr) => Some(constructor.clone()(vec![expr, new_expr])),
None => Some(new_expr),
}
}
#[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(inner) => match eval(inner, truthy, falsy) {
Value::True => Value::False,
Value::False => Value::True,
Value::Expr(e) => Value::Expr(Expr::Not(Box::new(e))),
},
Expr::And(operands) => {
let mut simplified = vec![];
for operand in operands {
match eval(operand, truthy, falsy) {
Value::True => continue,
Value::False => return Value::False,
Value::Expr(e) => simplified.push(e),
}
}
match simplified.len() {
0 => Value::True,
1 => Value::Expr(simplified.pop().unwrap()),
_ => Value::Expr(Expr::And(simplified)),
}
}
Expr::Or(operands) => {
let mut simplified = vec![];
for operand in operands {
match eval(operand, truthy, falsy) {
Value::True => return Value::True,
Value::False => continue,
Value::Expr(e) => simplified.push(e),
}
}
match simplified.len() {
0 => Value::False,
1 => Value::Expr(simplified.pop().unwrap()),
_ => Value::Expr(Expr::Or(simplified)),
}
}
}
}
macro_rules! expr {
(atom($c:expr)) => {
Expr::Atom($c)
};
(not($e:tt)) => {
Expr::Not(Box::new(expr!($e)))
};
(and($($e:tt),*)) => {
Expr::And(vec![$(expr!($e)),*])
};
(or($($e:tt),*)) => {
Expr::Or(vec![$(expr!($e)),*])
};
(($($e:tt)*)) => {
expr!($($e)*)
};
}

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

Compiling solution v0.1.0 (/tmp/d20241224-258381-av1cvu/solution)
warning: unused macro definition: `expr`
   --> src/lib.rs:225:14
    |
225 | macro_rules! expr {
    |              ^^^^
    |
    = note: `#[warn(unused_macros)]` on by default

warning: `solution` (lib) generated 1 warning
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.72s
     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 ... ok
test solution_test::test_eval_unwrap_and_or ... ok
test solution_test::test_eval_unwrap_nested ... ok
test solution_test::test_paren_around_expr ... FAILED
test solution_test::test_paren_expr_priority ... FAILED
test solution_test::test_paren_nested ... FAILED
test solution_test::test_paren_not ... FAILED
test solution_test::test_paren_surrounded ... FAILED
test solution_test::test_parser_alternating_ops ... ok
test solution_test::test_parser_atom ... ok
test solution_test::test_parser_and_or ... ok
test solution_test::test_parser_error_unexpected_end ... FAILED
test solution_test::test_parser_errors_basic ... FAILED
test solution_test::test_parser_multiple_atoms_same_op ... ok
test solution_test::test_parser_expr_and_not ... FAILED
test solution_test::test_parser_multiple_not ... FAILED
test solution_test::test_parser_not ... ok

failures:

---- solution_test::test_error_paren_mismatched stdout ----
thread '<unnamed>' panicked at 'called `Result::unwrap()` on an `Err` value: UnexpectedUnaryOp', tests/solution_test.rs:336:29
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
thread 'solution_test::test_error_paren_mismatched' panicked at 'called `Result::unwrap()` on an `Err` value: UnexpectedUnaryOp', tests/solution_test.rs:325:5

---- solution_test::test_paren_around_expr stdout ----
thread '<unnamed>' panicked at 'called `Result::unwrap()` on an `Err` value: UnexpectedUnaryOp', tests/solution_test.rs:182:43
thread 'solution_test::test_paren_around_expr' panicked at 'called `Result::unwrap()` on an `Err` value: UnexpectedUnaryOp', tests/solution_test.rs:176:5

---- solution_test::test_paren_expr_priority stdout ----
thread '<unnamed>' panicked at 'called `Result::unwrap()` on an `Err` value: UnexpectedUnaryOp', tests/solution_test.rs:199:47
thread 'solution_test::test_paren_expr_priority' panicked at 'called `Result::unwrap()` on an `Err` value: UnexpectedUnaryOp', tests/solution_test.rs:197: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_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_surrounded stdout ----
thread '<unnamed>' panicked at 'called `Result::unwrap()` on an `Err` value: UnexpectedUnaryOp', tests/solution_test.rs:237:61
thread 'solution_test::test_paren_surrounded' panicked at 'called `Result::unwrap()` on an `Err` value: UnexpectedUnaryOp', tests/solution_test.rs:235: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_errors_basic stdout ----
thread '<unnamed>' panicked at 'assertion failed: matches!(parser.push_op(\'!\'), Err(_))', tests/solution_test.rs:278: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_expr_and_not stdout ----
thread '<unnamed>' panicked at 'called `Result::unwrap()` on an `Err` value: UnexpectedBinOp', tests/solution_test.rs:109:44
thread 'solution_test::test_parser_expr_and_not' panicked at 'called `Result::unwrap()` on an `Err` value: UnexpectedBinOp', tests/solution_test.rs:107:5

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


failures:
    solution_test::test_error_paren_mismatched
    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_error_unexpected_end
    solution_test::test_parser_errors_basic
    solution_test::test_parser_expr_and_not
    solution_test::test_parser_multiple_not

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

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

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

Йоанна качи първо решение на 22.12.2024 23:49 (преди 9 месеца)