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

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

Към профила на Станислав Стаматов

Резултати

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

Код

#[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 {
// ...
last_symbol: char,
op_vec: Vec<char>,
item_vec: Vec<Expr>,
}
impl SimpleExprParser {
pub fn new() -> SimpleExprParser {
//todo!();
Self {
last_symbol: '\0',
op_vec: vec![],
item_vec: vec![],
}
}
/// Приема атом.
///
/// `c` ще бъде валиден символ за атом.
/// В противен случай можете да panic-нете (няма да се тества)
pub fn push_atom(&mut self, c: char) -> Result<(), ParseError> {
//todo!()
if !c.is_alphabetic() {
return Err(ParseError::UnexpectedExpr);
}
if self.last_symbol.is_alphabetic() {
return Err(ParseError::UnexpectedExpr);
}
self.item_vec.push(Expr::Atom(c));
self.last_symbol = c;
Ok(())
}
/// Приема символ за операция.
///
/// `op` ще бъде едно от '&', '|', '!'.
/// В противен случай можете да panic-нете (няма да се тества)
pub fn push_op(&mut self, op: char) -> Result<(), ParseError> {
//todo!()
if op != '!' && (self.last_symbol == '|' || self.last_symbol == '&') {
return Err(ParseError::UnexpectedBinOp);
}
match op {
'!' => {}
'|' => {
if !self.op_vec.is_empty() && *self.op_vec.last().unwrap() != '|' {
self.resolve_op()?;
}
}
'&' => {
if !self.op_vec.is_empty() && *self.op_vec.last().unwrap() != '&' {
self.resolve_op()?;
}
}
_ => return Err(ParseError::UnexpectedBinOp),
}
if !(!self.op_vec.is_empty()
&& (op == '&' || op == '|') //if we want to add more combined symbols
&& *self.op_vec.last().unwrap() == op)
{
self.op_vec.push(op);
}
self.last_symbol = op;
Ok(())
}
pub fn resolve_op(&mut self) -> Result<(), ParseError> {
while let Some(op) = self.op_vec.pop() {
match op {
'!' => {
if let Some(expr) = self.item_vec.pop() {
self.item_vec.push(Expr::Not(Box::new(expr)));
/////////////////////////////////////////
//print(&self.item_vec.last().unwrap());
//println!("");
} else {
return Err(ParseError::UnexpectedExpr);
}
}
'&' | '|' => {
let mut curr_vec = vec![];
if self.item_vec.len() < 2 {
return Err(ParseError::UnexpectedExpr);
}
while let Some(val) = self.item_vec.pop() {
curr_vec.push(val);
}
let comb_expr = match op {
'&' => Expr::And(curr_vec),
'|' => Expr::Or(curr_vec),
_ => panic!(),
};
self.item_vec.push(comb_expr);
/////////////////////////////////////////
//print(&self.item_vec.last().unwrap());
//println!("");
}
_ => return Err(ParseError::UnexpectedBinOp),
}
}
Ok(())
}
/// Завършва парсването и връща построения израз.
pub fn finish(&mut self) -> Result<Expr, ParseError> {
//todo!()
while !self.op_vec.is_empty() {
self.resolve_op()?;
}
/////////////////////////////////////////
print(&self.item_vec.last().unwrap());
println!("");
/////////////////////////////////////////
if self.item_vec.len() == 1 {
Ok(self.item_vec.pop().unwrap())
} else {
Err(ParseError::UnexpectedEnd)
}
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum Value {
True,
False,
Expr(Expr),
}
pub fn print(expr: &Expr) {
//todo!()
match expr {
Expr::Atom(ch) => {
print!("{}", ch);
}
Expr::Not(sub_expr) => {
print!("Not(");
print(sub_expr);
print!(")");
}
Expr::And(sub_expr) => {
print!("And(");
for sub in sub_expr {
print(sub);
print!(",");
}
print!(")");
}
Expr::Or(sub_expr) => {
print!("Or(");
for sub in sub_expr {
print(sub);
print!(",");
}
print!(")");
}
}
}
pub fn eval(expr: &Expr, truthy: &[char], falsy: &[char]) -> Value {
//todo!()
match expr {
Expr::Atom(ch) => {
if truthy.contains(ch) {
Value::True
} else if falsy.contains(ch) {
Value::False
} else {
Value::Expr(Expr::Atom(*ch))
}
}
Expr::Not(sub_expr) => match eval(sub_expr, truthy, falsy) {
Value::True => Value::False,
Value::False => Value::True,
Value::Expr(inner) => Value::Expr(Expr::Not(Box::new(inner))),
},
Expr::And(sub_expr) => {
let mut unval = vec![];
for sub in sub_expr {
match eval(sub, truthy, falsy) {
Value::True => continue,
Value::False => return Value::False,
Value::Expr(inner) => unval.push(inner),
}
}
if unval.is_empty() {
Value::True
} else {
Value::Expr(Expr::And(unval))
}
}
Expr::Or(sub_expr) => {
let mut unval = vec![];
for sub in sub_expr {
match eval(sub, truthy, falsy) {
Value::True => return Value::True,
Value::False => continue,
Value::Expr(inner) => unval.push(inner),
}
}
if unval.is_empty() {
Value::False
} else {
Value::Expr(Expr::Or(unval))
}
}
}
}
/// Парсър за пълния израз
pub struct ExprParser {
// ...
last_symbol: char,
op_vec: Vec<char>,
item_vec: Vec<Expr>,
}
impl ExprParser {
pub fn new() -> ExprParser {
//todo!();
Self {
last_symbol: '\0',
op_vec: vec![],
item_vec: vec![],
}
}
/// Приема атом.
///
/// `c` ще бъде валиден символ за атом.
/// В противен случай можете да panic-нете (няма да се тества)
pub fn push_atom(&mut self, c: char) -> Result<(), ParseError> {
//todo!()
//todo!()
if !c.is_alphabetic() {
return Err(ParseError::UnexpectedExpr);
}
if self.last_symbol.is_alphabetic() {
return Err(ParseError::UnexpectedExpr);
}
self.item_vec.push(Expr::Atom(c));
self.last_symbol = c;
Ok(())
}
/// Приема символ за операция.
///
/// `op` ще бъде едно от '&', '|', '!'.
/// В противен случай можете да panic-нете (няма да се тества)
pub fn push_op(&mut self, op: char) -> Result<(), ParseError> {
//todo!()
if op != '!' && (self.last_symbol == '|' || self.last_symbol == '&') {
return Err(ParseError::UnexpectedBinOp);
}
match op {
'!' => {}
'|' => {
if !self.op_vec.is_empty() && *self.op_vec.last().unwrap() != '|' {
self.resolve_op()?;
}
}
'&' => {
if !self.op_vec.is_empty() && *self.op_vec.last().unwrap() != '&' {
self.resolve_op()?;
}
}
_ => return Err(ParseError::UnexpectedBinOp),
}
//if !(!self.op_vec.is_empty()
// && (op == '&' || op == '|') //if we want to add more combined symbols
// && *self.op_vec.last().unwrap() == op)
//{
// self.op_vec.push(op);
//}
self.op_vec.push(op);
self.last_symbol = op;
Ok(())
}
/// Приема отваряща скоба.
pub fn open_paren(&mut self) -> Result<(), ParseError> {
//todo!()
self.op_vec.push('(');
self.item_vec.push(Expr::Atom('('));
Ok(())
}
/// Приема затваряща скоба.
pub fn close_paren(&mut self) -> Result<(), ParseError> {
//todo!()
if !self.op_vec.contains(&'(') {
return Err(ParseError::UnexpectedParen);
}
self.resolve_op()?;
Ok(())
}
//трябва да му се оправи условието на whila-a
pub fn resolve_op(&mut self) -> Result<(), ParseError> {
while let Some(op) = self.op_vec.pop() {
match op {
'!' => {
if let Some(expr) = self.item_vec.pop() {
self.item_vec.push(Expr::Not(Box::new(expr)));
/////////////////////////////////////////
//print(&self.item_vec.last().unwrap());
//println!("");
} else {
return Err(ParseError::UnexpectedExpr);
}
}
'&' | '|' => {
//тук има грешка защото & и | засмукват всички item-и
let mut curr_vec = vec![];
if self.item_vec.len() < 2 {
return Err(ParseError::UnexpectedExpr);
}
while let Some(val) = self.item_vec.pop() {
if val == Expr::Atom('(') {
break;
}
curr_vec.push(val);
}
let comb_expr = match op {
'&' => Expr::And(curr_vec),
'|' => Expr::Or(curr_vec),
_ => panic!(),
};
self.item_vec.push(comb_expr);
/*
if let (Some(left), Some(right)) = (self.item_vec.pop(), self.item_vec.pop()) {
let comb_expr = match op {
'&' => Expr::And(vec![left, right]),
'|' => Expr::Or(vec![left, right]),
_ => panic!(),
};
self.item_vec.push(comb_expr);
} else {
return Err(ParseError::UnexpectedExpr);
}*/
/////////////////////////////////////////
//print(&self.item_vec.last().unwrap());
//println!("");
}
'(' => {
break;
}
_ => return Err(ParseError::UnexpectedBinOp),
}
}
Ok(())
}
/// Завършва парсването и връща построения израз.
pub fn finish(mut self) -> Result<Expr, ParseError> {
//todo!()
while !self.op_vec.is_empty() {
self.resolve_op()?;
}
/////////////////////////////////////////
print(&self.item_vec.last().unwrap());
println!("");
println!("{}", self.item_vec.len());
println!("{}", self.op_vec.len());
/////////////////////////////////////////
if self.item_vec.len() == 1 {
Ok(self.item_vec.pop().unwrap())
} else {
println!("boom from finish");
Err(ParseError::UnexpectedEnd)
}
}
}

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

Compiling solution v0.1.0 (/tmp/d20241224-258381-17ukhzw/solution)
    Finished test [unoptimized + debuginfo] target(s) in 1.71s
     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_nested ... FAILED
test solution_test::test_eval_unwrap_and_or ... 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_paren_surrounded ... FAILED
test solution_test::test_parser_alternating_ops ... FAILED
test solution_test::test_parser_and_or ... FAILED
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_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 ... 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_eval_unwrap_nested stdout ----
thread '<unnamed>' panicked at 'assertion failed: `(left == right)`
  left: `Expr(Or([Atom('X'), And([Atom('B')]), Not(And([Atom('D')])), Atom('Y')]))`,
 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: `Expr(Or([Atom('X'), And([Atom('B')]), Not(And([Atom('D')])), Atom('Y')]))`,
 right: `Expr(Or([Atom('X'), Atom('B'), Not(Atom('D')), Atom('Y')]))`', tests/solution_test.rs:479:5

---- solution_test::test_eval_unwrap_and_or stdout ----
thread '<unnamed>' panicked at 'assertion failed: `(left == right)`
  left: `Expr(And([Atom('B')]))`,
 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: `Expr(And([Atom('B')]))`,
 right: `Expr(Atom('B'))`', tests/solution_test.rs:456:5

---- solution_test::test_paren_around_expr stdout ----
A
2
0
boom from finish
thread '<unnamed>' panicked at 'called `Result::unwrap()` on an `Err` value: UnexpectedEnd', tests/solution_test.rs:179:36
thread 'solution_test::test_paren_around_expr' panicked at 'called `Result::unwrap()` on an `Err` value: UnexpectedEnd', tests/solution_test.rs:176:5

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

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

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

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

---- solution_test::test_parser_alternating_ops stdout ----
And(D,Or(C,And(B,A,),),)
thread '<unnamed>' panicked at 'assertion failed: `(left == right)`
  left: `And([Atom('D'), Or([Atom('C'), And([Atom('B'), Atom('A')])])])`,
 right: `And([Or([And([Atom('A'), Atom('B')]), Atom('C')]), Atom('D')])`', tests/solution_test.rs:160:9
thread 'solution_test::test_parser_alternating_ops' panicked at 'assertion failed: `(left == right)`
  left: `And([Atom('D'), Or([Atom('C'), And([Atom('B'), Atom('A')])])])`,
 right: `And([Or([And([Atom('A'), Atom('B')]), Atom('C')]), Atom('D')])`', tests/solution_test.rs:157:5

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

---- solution_test::test_parser_error_unexpected_end stdout ----
thread '<unnamed>' panicked at 'called `Option::unwrap()` on a `None` value', src/lib.rs:130:37
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 ----
And(Not(B),A,)
thread '<unnamed>' panicked at 'assertion failed: `(left == right)`
  left: `And([Not(Atom('B')), Atom('A')])`,
 right: `And([Atom('A'), Not(Atom('B'))])`', tests/solution_test.rs:110:9
thread 'solution_test::test_parser_expr_and_not' panicked at 'assertion failed: `(left == right)`
  left: `And([Not(Atom('B')), Atom('A')])`,
 right: `And([Atom('A'), Not(Atom('B'))])`', tests/solution_test.rs:107:5

---- solution_test::test_parser_multiple_atoms_same_op stdout ----
And(C,B,A,)
thread '<unnamed>' panicked at 'assertion failed: `(left == right)`
  left: `And([Atom('C'), Atom('B'), Atom('A')])`,
 right: `And([Atom('A'), Atom('B'), Atom('C')])`', tests/solution_test.rs:127:9
thread 'solution_test::test_parser_multiple_atoms_same_op' panicked at 'assertion failed: `(left == right)`
  left: `And([Atom('C'), Atom('B'), Atom('A')])`,
 right: `And([Atom('A'), Atom('B'), Atom('C')])`', tests/solution_test.rs:124:5

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


failures:
    solution_test::test_error_paren_mismatched
    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

test result: FAILED. 5 passed; 15 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 17:24 (преди 9 месеца)