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

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

Към профила на Карина Георгиева

Резултати

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

Код

#[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 {
expr: Option<Expr>,
last_op: Option<char>
}
impl SimpleExprParser {
pub fn new() -> SimpleExprParser {
SimpleExprParser {
expr: None,
last_op: None
}
}
pub fn push_atom(&mut self, c: char) -> Result<(), ParseError> {
if self.is_invalid_char(c) {
return Err(ParseError::UnexpectedExpr);
}
if self.last_op.is_none() {
if self.expr.is_none() {
self.expr = Some(Expr::Atom(c));
Ok(())
} else {
return Err(ParseError::UnexpectedExpr);
}
} else {
match self.last_op {
Some('!') => {
if self.expr.is_none() {
self.expr = Some(Expr::Not(Box::new(Expr::Atom(c))));
} else {
if let Some(Expr::And(ref mut vec)) = self.expr {
vec.push(Expr::Not(Box::new(Expr::Atom(c))));
} else if let Some(Expr::Or(ref mut vec)) = self.expr {
vec.push(Expr::Not(Box::new(Expr::Atom(c))));
}
}
}
Some('&') => {
if self.expr.is_none() {
return Err(ParseError::UnexpectedBinOp);
}
let
current_expr = self.expr.take();
self.expr = Some(match current_expr {
Some(Expr::And(mut vec)) => {
vec.push(Expr::Atom(c));
Expr::And(vec)
}
Some(other_expr) => Expr::And(vec![other_expr, Expr::Atom(c)]),
_ => return Err(ParseError::UnexpectedUnaryOp),
});
}
Some('|') => {
if self.expr.is_none() {
return Err(ParseError::UnexpectedBinOp);
}
let
current_expr = self.expr.take();
self.expr = Some(match current_expr {
Some(Expr::Or(mut vec)) => {
vec.push(Expr::Atom(c));
Expr::Or(vec)
}
Some(other_expr) => Expr::Or(vec![other_expr, Expr::Atom(c)]),
_ => return Err(ParseError::UnexpectedUnaryOp),
});
}
_ => return Err(ParseError::UnexpectedUnaryOp),
}
self.last_op = None;
Ok(())
}
}
pub fn push_op(&mut self, op: char) -> Result<(), ParseError> {
if let Some(last_op) = self.last_op {
if last_op == '!' && op == '!' {
self.last_op = None;
} else {
return Err(ParseError::UnexpectedBinOp);
}
} else {
self.last_op = Some(op);
}
Ok(())
}
pub fn finish(self) -> Result<Expr, ParseError> {
if self.expr.is_some() {
Ok(self.expr.unwrap())
} else {
Err(ParseError::UnexpectedEnd)
}
}
fn is_invalid_char(&self, c: char) -> bool {
let invalid_chars = [' ', '&', '|', '!', '(', ')'];
invalid_chars.contains(&c)
}
}
pub struct ExprParser {
stack: Vec<Expr>,
ops: Vec<char>,
}
impl ExprParser {
pub fn new() -> ExprParser {
ExprParser {
stack: Vec::new(),
ops: Vec::new(),
}
}
pub fn push_atom(&mut self, c: char) -> Result<(), ParseError> {
self.stack.push(Expr::Atom(c));
self.reduce()
}
pub fn push_op(&mut self, op: char) -> Result<(), ParseError> {
if op == '!' {
self.ops.push(op);
} else {
while let Some(&last_op) = self.ops.last() {
if last_op == '!' || last_op == '(' {
break;
}
self.reduce_op()?;
}
self.ops.push(op);
}
Ok(())
}
pub fn open_paren(&mut self) -> Result<(), ParseError> {
self.ops.push('(');
Ok(())
}
pub fn close_paren(&mut self) -> Result<(), ParseError> {
while let Some(op) = self.ops.pop() {
if op == '(' {
return Ok(());
}
self.reduce_op_with(op)?;
}
Err(ParseError::UnexpectedParen)
}
pub fn finish(mut self) -> Result<Expr, ParseError> {
while let Some(op) = self.ops.pop() {
self.reduce_op_with(op)?;
}
if self.stack.len() != 1 {
return Err(ParseError::UnexpectedEnd);
}
Ok(self.stack.pop().unwrap())
}
fn reduce(&mut self) -> Result<(), ParseError> {
while let Some(&op) = self.ops.last() {
if op == '!' {
self.ops.pop();
let expr = self.stack.pop().ok_or(ParseError::UnexpectedEnd)?;
self.stack.push(Expr::Not(Box::new(expr)));
} else {
break;
}
}
Ok(())
}
fn reduce_op(&mut self) -> Result<(), ParseError> {
let op = self.ops.pop().ok_or(ParseError::UnexpectedEnd)?;
self.reduce_op_with(op)
}
fn reduce_op_with(&mut self, op: char) -> Result<(), ParseError> {
let right = self.stack.pop().ok_or(ParseError::UnexpectedEnd)?;
let left = self.stack.pop().ok_or(ParseError::UnexpectedEnd)?;
let new_expr = match op {
'&' => {
if let Expr::And(mut vec) = left {
vec.push(right);
Expr::And(vec)
} else if let Expr::And(mut vec) = right {
vec.insert(0, left);
Expr::And(vec)
} else {
Expr::And(vec![left, right])
}
}
'|' => {
if let Expr::Or(mut vec) = left {
vec.push(right);
Expr::Or(vec)
} else if let Expr::Or(mut vec) = right {
vec.insert(0, left);
Expr::Or(vec)
} else {
Expr::Or(vec![left, right])
}
}
_ => return Err(ParseError::UnexpectedUnaryOp),
};
self.stack.push(new_expr);
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) => match eval(e, truthy, falsy) {
Value::True => Value::False,
Value::False => Value::True,
Value::Expr(e) => Value::Expr(Expr::Not(Box::new(e))),
},
Expr::And(exprs) => {
let mut new_exprs = Vec::new();
for e in exprs {
match eval(e, truthy, falsy) {
Value::True => continue,
Value::False => return Value::False,
Value::Expr(e) => new_exprs.push(e),
}
}
if new_exprs.is_empty() {
Value::True
} else if new_exprs.len() == 1 {
Value::Expr(new_exprs.pop().unwrap())
} else {
Value::Expr(Expr::And(new_exprs))
}
}
Expr::Or(exprs) => {
let mut new_exprs = Vec::new();
for e in exprs {
match eval(e, truthy, falsy) {
Value::True => return Value::True,
Value::False => continue,
Value::Expr(e) => new_exprs.push(e),
}
}
if new_exprs.is_empty() {
Value::False
} else if new_exprs.len() == 1 {
Value::Expr(new_exprs.pop().unwrap())
} else {
Value::Expr(Expr::Or(new_exprs))
}
}
}
}

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

Compiling solution v0.1.0 (/tmp/d20241224-258381-1awhqpj/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.69s
     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_unwrap_and_or ... ok
test solution_test::test_eval_partial ... ok
test solution_test::test_eval_unwrap_nested ... ok
test solution_test::test_paren_around_expr ... ok
test solution_test::test_paren_expr_priority ... ok
test solution_test::test_paren_nested ... FAILED
test solution_test::test_paren_not ... FAILED
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 ... 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 'assertion failed: matches!(parser.close_paren(), Err(_))', tests/solution_test.rs:331: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_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:220:29
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_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: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_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 'assertion failed: `(left == right)`
  left: `Not(Atom('B'))`,
 right: `Not(Not(Not(Atom('B'))))`', tests/solution_test.rs:143:9
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_error_paren_mismatched
    solution_test::test_paren_nested
    solution_test::test_paren_not
    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. 13 passed; 7 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:46 (преди 9 месеца)