Решение на Логически изрази от Стоян Дарджиков

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

Към профила на Стоян Дарджиков

Резултати

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

Код

#[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 {
expression: Option<Expr>,
operations: Vec<char>,
is_waiting_atom_or_unary: bool,
}
impl SimpleExprParser {
pub fn new() -> SimpleExprParser {
SimpleExprParser{expression: None, operations: Vec::new(), is_waiting_atom_or_unary: true}
}
pub fn push_atom(&mut self, c: char) -> Result<(), ParseError> {
if !self.is_waiting_atom_or_unary {
return Err(ParseError::UnexpectedExpr);
}
let mut atom = Expr::Atom(c);
while !self.operations.is_empty() && *self.operations.last().unwrap() == '!' {
atom = Expr::Not(Box::new(atom));
self.operations.pop();
}
if self.operations.is_empty() {
self.expression = Some(atom);
self.is_waiting_atom_or_unary = false;
return Ok(());
}
let mut expr = self.expression.clone().unwrap();
match self.operations.last().unwrap() {
'&' => {
match expr {
Expr::And(ref mut vec) => {
vec.push(atom);
}
_ => {
return Err(ParseError::UnexpectedEnd);
}
}
}
'|' => {
match expr {
Expr::Or(ref mut vec) => {
vec.push(atom);
}
_ => {
return Err(ParseError::UnexpectedEnd);
}
}
}
_ => {return Err(ParseError::UnexpectedEnd);}
}
self.expression = Some(expr);
self.is_waiting_atom_or_unary = false;
Ok(())
}
pub fn push_op(&mut self, op: char) -> Result<(), ParseError> {
match op {
'!' => {
if !self.is_waiting_atom_or_unary {
return Err(ParseError::UnexpectedUnaryOp);
}
self.operations.push(op);
}
'|' => {
if self.is_waiting_atom_or_unary {
return Err(ParseError::UnexpectedBinOp);
}
let expression = self.expression.clone().unwrap();
match expression {
Expr::Or(_) => {
}
_ => {
self.expression = Some(Expr::Or(vec![expression]));
self.operations.push(op);
}
}
self.is_waiting_atom_or_unary = true;
}
'&' => {
if self.is_waiting_atom_or_unary {
return Err(ParseError::UnexpectedBinOp);
}
let expression = self.expression.clone().unwrap();
match expression {
Expr::And(_) => {
}
_ => {
self.expression = Some(Expr::And(vec![expression]));
self.operations.push(op);
}
}
self.is_waiting_atom_or_unary = true;
}
_ => panic!("Неочакванa перация: {}", op),
}
Ok(())
}
pub fn finish(self) -> Result<Expr, ParseError> {
match self.expression {
Some(expr) => {
Ok(expr)
}
None => {
Err(ParseError::UnexpectedExpr)
}
}
}
}
#[derive(Debug, PartialEq, Eq)]
pub struct ParanExpr {
prev_expr: Option<Expr>,
next_is_not: bool,
}
pub struct ExprParser {
expression: Option<Expr>,
operations: Vec<char>,
is_waiting_atom_or_unary: bool,
has_operator_not: i32,
paren_stack: Vec<ParanExpr>,
}
impl ExprParser {
pub fn new() -> ExprParser {
ExprParser {
expression: None,
operations: Vec::new(),
is_waiting_atom_or_unary: true,
has_operator_not: 0,
paren_stack: Vec::new(),
}
}
pub fn push_atom(&mut self, c: char) -> Result<(), ParseError> {
if !self.is_waiting_atom_or_unary {
return Err(ParseError::UnexpectedExpr);
}
let mut atom = Expr::Atom(c);
while self.has_operator_not > 0 {
atom = Expr::Not(Box::new(atom));
self.has_operator_not -= 1;
}
if self.operations.is_empty() {
self.expression = Some(atom);
self.is_waiting_atom_or_unary = false;
return Ok(());
}
let mut expr = self.expression.clone().unwrap();
match self.operations.last().unwrap() {
'&' => {
match expr {
Expr::And(ref mut vec) => {
vec.push(atom);
}
_ => {
return Err(ParseError::UnexpectedEnd);
}
}
}
'|' => {
match expr {
Expr::Or(ref mut vec) => {
vec.push(atom);
}
_ => {
return Err(ParseError::UnexpectedEnd);
}
}
}
_ => ()
}
self.expression = Some(expr);
self.is_waiting_atom_or_unary = false;
Ok(())
}
pub fn push_op(&mut self, op: char) -> Result<(), ParseError> {
match op {
'!' => {
if !self.is_waiting_atom_or_unary {
return Err(ParseError::UnexpectedUnaryOp);
}
self.has_operator_not += 1;
}
'|' => {
if self.is_waiting_atom_or_unary {
return Err(ParseError::UnexpectedBinOp);
}
let expression = self.expression.clone().unwrap();
match expression {
Expr::Or(_) => {
}
_ => {
self.expression = Some(Expr::Or(vec![expression]));
self.operations.push(op);
}
}
self.is_waiting_atom_or_unary = true;
}
'&' => {
if self.is_waiting_atom_or_unary {
return Err(ParseError::UnexpectedBinOp);
}
let expression = self.expression.clone().unwrap();
match expression {
Expr::And(_) => {
}
_ => {
self.expression = Some(Expr::And(vec![expression]));
self.operations.push(op);
}
}
self.is_waiting_atom_or_unary = true;
}
_ => panic!("Неочакванa перация: {}", op),
}
Ok(())
}
pub fn open_paren(&mut self) -> Result<(), ParseError> {
if !self.is_waiting_atom_or_unary {
return Err(ParseError::UnexpectedParen);
}
self.paren_stack.push(ParanExpr {prev_expr: self.expression.clone(), next_is_not: self.has_operator_not > 0 });
self.expression = None;
self.operations = Vec::new();
if self.has_operator_not > 0 {
self.has_operator_not -= 1;
}
Ok(())
}
pub fn close_paren(&mut self) -> Result<(), ParseError> {
if self.paren_stack.is_empty() {
return Err(ParseError::UnexpectedParen);
}
let expr = self.expression.take().unwrap_or(Expr::Atom(' '));
if let Some(paran_expr_optoin) = self.paren_stack.pop() {
match paran_expr_optoin.prev_expr {
Some(prev_expr_value) => {
match prev_expr_value {
Expr::And(mut vec) => {
if paran_expr_optoin.next_is_not {
vec.push(Expr::Not(Box::new(expr)));
} else {
vec.push(expr);
}
self.expression = Some(Expr::And(vec));
self.has_operator_not -= 1;
}
Expr::Or(mut vec) => {
if paran_expr_optoin.next_is_not {
vec.push(Expr::Not(Box::new(expr)));
} else {
vec.push(expr);
}
self.expression = Some(Expr::Or(vec));
self.has_operator_not -= 1;
}
_ => return Err(ParseError::UnexpectedParen),
}
}
None => {
self.expression = Some(expr);
}
}
} else {
self.expression = Some(expr);
}
self.is_waiting_atom_or_unary = false;
Ok(())
}
pub fn finish(self) -> Result<Expr, ParseError> {
match self.expression {
Some(expr) => {
Ok(expr)
}
None => {
Err(ParseError::UnexpectedExpr)
}
}
}
}
#[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::And(ref vec) => {
let mut values = Vec::<Expr>::new();
for expr in vec {
let val = eval(expr, truthy, falsy);
match val {
Value::True => {}
Value::False => {
return Value::False;
}
Value::Expr(ex) => {
values.push(ex);
}
}
}
if values.len() < 1 {
return Value::True;
}
if values.len() == 1 {
return Value::Expr(values[0].clone());
}
return Value::Expr(Expr::And(values));
}
Expr::Or(ref vec) => {
let mut values = Vec::<Expr>::new();
for expr in vec {
let val = eval(expr, truthy, falsy);
match val {
Value::False => {}
Value::True => {
return Value::True;
}
Value::Expr(ex) => {
values.push(ex);
}
}
}
if values.len() < 1 {
return Value::False;
}
if values.len() == 1 {
return Value::Expr(values[0].clone());
}
return Value::Expr(Expr::Or(values));
}
Expr::Atom(c) => {
if truthy.contains(c) {
return Value::True;
}
if falsy.contains(c) {
return Value::False;
}
return Value::Expr(Expr::Atom(*c));
}
Expr::Not(ref b) => {
let value = eval(b, truthy, falsy);
match value {
Value::True => {return Value::False;}
Value::False => {return Value::True;}
Value::Expr(ex) => {
match ex.clone() {
Expr::Not(expr_not) => {
return Value::Expr(*expr_not);
}
_ => {
return Value::Expr(Expr::Not(Box::new(ex)));
}
}
}
}
}
}
}

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

Compiling solution v0.1.0 (/tmp/d20241224-258381-1rzt0ah/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.77s
     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_expr_priority ... ok
test solution_test::test_paren_around_expr ... ok
test solution_test::test_paren_nested ... FAILED
test solution_test::test_paren_not ... FAILED
test solution_test::test_parser_alternating_ops ... ok
test solution_test::test_paren_surrounded ... FAILED
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 ... 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 ... 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 'assertion failed: `(left == right)`
  left: `And([Atom('A'), Not(And([Atom('B'), Not(And([Atom('C'), Atom('D')]))]))])`,
 right: `Not(And([Atom('A'), Not(And([Atom('B'), Not(And([Atom('C'), Atom('D')]))]))]))`', tests/solution_test.rs:255:9
thread 'solution_test::test_paren_nested' panicked at 'assertion failed: `(left == right)`
  left: `And([Atom('A'), Not(And([Atom('B'), Not(And([Atom('C'), Atom('D')]))]))])`,
 right: `Not(And([Atom('A'), Not(And([Atom('B'), Not(And([Atom('C'), Atom('D')]))]))]))`', tests/solution_test.rs:252:5

---- solution_test::test_paren_not stdout ----
thread '<unnamed>' panicked at 'assertion failed: `(left == right)`
  left: `Or([Atom('A'), Atom('B'), Atom('X')])`,
 right: `Or([Not(Or([Atom('A'), Atom('B')])), Atom('X')])`', tests/solution_test.rs:226:9
thread 'solution_test::test_paren_not' panicked at 'assertion failed: `(left == right)`
  left: `Or([Atom('A'), Atom('B'), Atom('X')])`,
 right: `Or([Not(Or([Atom('A'), Atom('B')])), Atom('X')])`', tests/solution_test.rs:216:5

---- solution_test::test_paren_surrounded stdout ----
thread '<unnamed>' panicked at 'called `Result::unwrap()` on an `Err` value: UnexpectedEnd', tests/solution_test.rs:237:61
thread 'solution_test::test_paren_surrounded' panicked at 'called `Result::unwrap()` on an `Err` value: UnexpectedEnd', 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


failures:
    solution_test::test_error_paren_mismatched
    solution_test::test_paren_nested
    solution_test::test_paren_not
    solution_test::test_paren_surrounded
    solution_test::test_parser_error_unexpected_end

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

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

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

Стоян качи първо решение на 21.12.2024 19:08 (преди 9 месеца)

Стоян качи решение на 21.12.2024 19:22 (преди 9 месеца)

#[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 {
expression: Option<Expr>,
operations: Vec<char>,
is_waiting_atom_or_unary: bool,
}
impl SimpleExprParser {
pub fn new() -> SimpleExprParser {
SimpleExprParser{expression: None, operations: Vec::new(), is_waiting_atom_or_unary: true}
}
pub fn push_atom(&mut self, c: char) -> Result<(), ParseError> {
if !self.is_waiting_atom_or_unary {
return Err(ParseError::UnexpectedExpr);
}
let mut atom = Expr::Atom(c);
- if !self.operations.is_empty() && *self.operations.last().unwrap() == '!' {
+ while !self.operations.is_empty() && *self.operations.last().unwrap() == '!' {
atom = Expr::Not(Box::new(atom));
self.operations.pop();
}
if self.operations.is_empty() {
self.expression = Some(atom);
self.is_waiting_atom_or_unary = false;
return Ok(());
}
let mut expr = self.expression.clone().unwrap();
match self.operations.last().unwrap() {
'&' => {
match expr {
Expr::And(ref mut vec) => {
vec.push(atom);
}
_ => {
return Err(ParseError::UnexpectedEnd);
}
}
}
'|' => {
match expr {
Expr::Or(ref mut vec) => {
vec.push(atom);
}
_ => {
return Err(ParseError::UnexpectedEnd);
}
}
}
_ => {return Err(ParseError::UnexpectedEnd);}
}
self.expression = Some(expr);
self.is_waiting_atom_or_unary = false;
Ok(())
}
pub fn push_op(&mut self, op: char) -> Result<(), ParseError> {
match op {
'!' => {
if !self.is_waiting_atom_or_unary {
return Err(ParseError::UnexpectedUnaryOp);
}
self.operations.push(op);
}
'|' => {
if self.is_waiting_atom_or_unary {
return Err(ParseError::UnexpectedBinOp);
}
let expression = self.expression.clone().unwrap();
match expression {
Expr::Or(_) => {
}
_ => {
self.expression = Some(Expr::Or(vec![expression]));
self.operations.push(op);
}
}
self.is_waiting_atom_or_unary = true;
}
'&' => {
if self.is_waiting_atom_or_unary {
return Err(ParseError::UnexpectedBinOp);
}
let expression = self.expression.clone().unwrap();
match expression {
Expr::And(_) => {
}
_ => {
self.expression = Some(Expr::And(vec![expression]));
self.operations.push(op);
}
}
self.is_waiting_atom_or_unary = true;
}
_ => panic!("Неочакванa перация: {}", op),
}
Ok(())
}
pub fn finish(self) -> Result<Expr, ParseError> {
match self.expression {
Some(expr) => {
Ok(expr)
}
None => {
Err(ParseError::UnexpectedExpr)
}
}
}
}
#[derive(Debug, PartialEq, Eq)]
pub struct ParanExpr {
prev_expr: Option<Expr>,
next_is_not: bool,
}
pub struct ExprParser {
expression: Option<Expr>,
operations: Vec<char>,
is_waiting_atom_or_unary: bool,
- has_operator_not: bool,
+ has_operator_not: i32,
paren_stack: Vec<ParanExpr>,
}
impl ExprParser {
pub fn new() -> ExprParser {
ExprParser {
expression: None,
operations: Vec::new(),
is_waiting_atom_or_unary: true,
- has_operator_not: false,
+ has_operator_not: 0,
paren_stack: Vec::new(),
}
}
pub fn push_atom(&mut self, c: char) -> Result<(), ParseError> {
if !self.is_waiting_atom_or_unary {
return Err(ParseError::UnexpectedExpr);
}
let mut atom = Expr::Atom(c);
- if self.has_operator_not {
- atom = Expr::Not(Box::new(atom));
+ while self.has_operator_not > 0 {
+ atom = Expr::Not(Box::new(atom));
+ self.has_operator_not -= 1;
}
if self.operations.is_empty() {
self.expression = Some(atom);
self.is_waiting_atom_or_unary = false;
return Ok(());
}
let mut expr = self.expression.clone().unwrap();
match self.operations.last().unwrap() {
'&' => {
match expr {
Expr::And(ref mut vec) => {
vec.push(atom);
}
_ => {
return Err(ParseError::UnexpectedEnd);
}
}
}
'|' => {
match expr {
Expr::Or(ref mut vec) => {
vec.push(atom);
}
_ => {
return Err(ParseError::UnexpectedEnd);
}
}
}
_ => ()
}
self.expression = Some(expr);
self.is_waiting_atom_or_unary = false;
Ok(())
}
pub fn push_op(&mut self, op: char) -> Result<(), ParseError> {
match op {
'!' => {
if !self.is_waiting_atom_or_unary {
return Err(ParseError::UnexpectedUnaryOp);
}
- self.has_operator_not = true;
+ self.has_operator_not += 1;
}
'|' => {
if self.is_waiting_atom_or_unary {
return Err(ParseError::UnexpectedBinOp);
}
let expression = self.expression.clone().unwrap();
match expression {
Expr::Or(_) => {
}
_ => {
self.expression = Some(Expr::Or(vec![expression]));
self.operations.push(op);
}
}
self.is_waiting_atom_or_unary = true;
}
'&' => {
if self.is_waiting_atom_or_unary {
return Err(ParseError::UnexpectedBinOp);
}
let expression = self.expression.clone().unwrap();
match expression {
Expr::And(_) => {
}
_ => {
self.expression = Some(Expr::And(vec![expression]));
self.operations.push(op);
}
}
self.is_waiting_atom_or_unary = true;
}
_ => panic!("Неочакванa перация: {}", op),
}
Ok(())
}
pub fn open_paren(&mut self) -> Result<(), ParseError> {
if !self.is_waiting_atom_or_unary {
return Err(ParseError::UnexpectedParen);
}
- self.paren_stack.push(ParanExpr {prev_expr: self.expression.clone(), next_is_not: self.has_operator_not });
+ self.paren_stack.push(ParanExpr {prev_expr: self.expression.clone(), next_is_not: self.has_operator_not > 0 });
self.expression = None;
self.operations = Vec::new();
- self.has_operator_not = false;
+ if self.has_operator_not > 0 {
+ self.has_operator_not -= 1;
+ }
Ok(())
}
pub fn close_paren(&mut self) -> Result<(), ParseError> {
if self.paren_stack.is_empty() {
return Err(ParseError::UnexpectedParen);
}
let expr = self.expression.take().unwrap_or(Expr::Atom(' '));
if let Some(paran_expr_optoin) = self.paren_stack.pop() {
match paran_expr_optoin.prev_expr {
Some(prev_expr_value) => {
match prev_expr_value {
Expr::And(mut vec) => {
if paran_expr_optoin.next_is_not {
vec.push(Expr::Not(Box::new(expr)));
} else {
vec.push(expr);
}
self.expression = Some(Expr::And(vec));
- self.has_operator_not = false;
+ self.has_operator_not -= 1;
}
Expr::Or(mut vec) => {
if paran_expr_optoin.next_is_not {
vec.push(Expr::Not(Box::new(expr)));
} else {
vec.push(expr);
}
self.expression = Some(Expr::Or(vec));
- self.has_operator_not = false;
+ self.has_operator_not -= 1;
}
_ => return Err(ParseError::UnexpectedParen),
}
}
None => {
self.expression = Some(expr);
}
}
} else {
self.expression = Some(expr);
}
self.is_waiting_atom_or_unary = false;
Ok(())
}
pub fn finish(self) -> Result<Expr, ParseError> {
match self.expression {
Some(expr) => {
Ok(expr)
}
None => {
Err(ParseError::UnexpectedExpr)
}
}
}
}
#[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::And(ref vec) => {
let mut values = Vec::<Expr>::new();
for expr in vec {
let val = eval(expr, truthy, falsy);
match val {
Value::True => {}
Value::False => {
return Value::False;
}
Value::Expr(ex) => {
values.push(ex);
}
}
}
if values.len() < 1 {
return Value::True;
}
if values.len() == 1 {
return Value::Expr(values[0].clone());
}
return Value::Expr(Expr::And(values));
}
Expr::Or(ref vec) => {
let mut values = Vec::<Expr>::new();
for expr in vec {
let val = eval(expr, truthy, falsy);
match val {
Value::False => {}
Value::True => {
return Value::True;
}
Value::Expr(ex) => {
values.push(ex);
}
}
}
if values.len() < 1 {
return Value::False;
}
if values.len() == 1 {
return Value::Expr(values[0].clone());
}
return Value::Expr(Expr::Or(values));
}
Expr::Atom(c) => {
if truthy.contains(c) {
return Value::True;
}
if falsy.contains(c) {
return Value::False;
}
return Value::Expr(Expr::Atom(*c));
}
Expr::Not(ref b) => {
let value = eval(b, truthy, falsy);
match value {
Value::True => {return Value::False;}
Value::False => {return Value::True;}
- Value::Expr(ex) => {return Value::Expr(Expr::Not(Box::new(ex)));}
+ Value::Expr(ex) => {
+ match ex.clone() {
+ Expr::Not(expr_not) => {
+ return Value::Expr(*expr_not);
+ }
+ _ => {
+ return Value::Expr(Expr::Not(Box::new(ex)));
+ }
+ }
+ }
}
}
}
}