Решение на Логически изрази от Александър Терезов

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

Към профила на Александър Терезов

Резултати

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

Код

#[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>,
last_was_atom: bool,
pending_not: bool,
}
impl SimpleExprParser {
pub fn new() -> SimpleExprParser {
SimpleExprParser {
current_expr: None,
last_was_atom: false,
pending_not: false,
}
}
pub fn push_atom(&mut self, c: char) -> Result<(), ParseError> {
if self.last_was_atom {
return Err(ParseError::UnexpectedExpr);
}
let mut atom_expr = Expr::Atom(c);
if self.pending_not {
atom_expr = Expr::Not(Box::new(atom_expr));
self.pending_not = false;
}
if let Some(Expr::And(ref mut terms)) = self.current_expr {
terms.push(atom_expr);
} else if let Some(Expr::Or(ref mut terms)) = self.current_expr {
terms.push(atom_expr);
} else {
self.current_expr = Some(atom_expr);
}
self.last_was_atom = true;
Ok(())
}
pub fn push_op(&mut self, op: char) -> Result<(), ParseError> {
if !self.last_was_atom && op != '!' {
return Err(ParseError::UnexpectedBinOp);
}
match op {
'&' => {
if let Some(Expr::Or(_)) = self.current_expr {
let and_expression = Some(Expr::And(vec![self.current_expr.take().unwrap()]));
self.current_expr = and_expression
}
if let Some(Expr::And(_)) = self.current_expr {
// We do nothing here
} else if let Some(atom) = self.current_expr.take() {
self.current_expr = Some(Expr::And(vec![atom]));
} else {
return Err(ParseError::UnexpectedEnd);
}
}
'|' => {
if let Some(Expr::And(_)) = self.current_expr {
let or_expression = Some(Expr::Or(vec![self.current_expr.take().unwrap()]));
self.current_expr = or_expression
}
if let Some(Expr::Or(_)) = self.current_expr {
// We do nothing here
} else if let Some(atom) = self.current_expr.take() {
self.current_expr = Some(Expr::Or(vec![atom]));
} else {
return Err(ParseError::UnexpectedEnd);
}
}
'!' => {
if self.last_was_atom {
return Err(ParseError::UnexpectedUnaryOp);
}
if self.pending_not {
return Err(ParseError::UnexpectedUnaryOp);
}
self.pending_not = true;
}
_ => panic!("Invalid operator"),
}
if op != '!' {
self.last_was_atom = false;
}
Ok(())
}
pub fn finish(self) -> Result<Expr, ParseError> {
self.current_expr.ok_or(ParseError::UnexpectedEnd)
}
}
pub struct ExprParser {
input: Vec<char>,
last_was_atom: bool,
open_parens: i32,
}
impl ExprParser {
pub fn new() -> ExprParser {
ExprParser {
input: Vec::new(),
last_was_atom: false,
open_parens: 0,
}
}
pub fn push_atom(&mut self, c: char) -> Result<(), ParseError> {
if self.last_was_atom {
return Err(ParseError::UnexpectedExpr);
}
self.input.push(c);
self.last_was_atom = true;
Ok(())
}
pub fn push_op(&mut self, op: char) -> Result<(), ParseError> {
if !self.last_was_atom && op != '!' {
return Err(ParseError::UnexpectedBinOp);
}
self.input.push(op);
if op != '!' {
self.last_was_atom = false;
}
Ok(())
}
pub fn open_paren(&mut self) -> Result<(), ParseError> {
if self.last_was_atom {
return Err(ParseError::UnexpectedParen);
}
self.input.push('(');
self.open_parens += 1;
Ok(())
}
pub fn close_paren(&mut self) -> Result<(), ParseError> {
if self.open_parens < 1 {
return Err(ParseError::UnexpectedParen);
}
self.input.push(')');
self.open_parens -= 1;
Ok(())
}
pub fn finish(self) -> Result<Expr, ParseError> {
if self.open_parens != 0 {
return Err(ParseError::UnexpectedParen);
}
if !self.last_was_atom {
return Err(ParseError::UnexpectedEnd);
}
println!("{:?}", self.input);
let result = self.recursive_parse(0)?;
println!("{:?}", result); // Debugging print
return Ok(result);
}
fn recursive_parse(&self, pos: usize) -> Result<Expr, ParseError> {
let mut current_expr: Option<Expr> = None;
let mut i = pos;
let mut pending_not = false;
while i < self.input.len() {
let c = self.input[i];
match c {
_ if !c.is_whitespace()
&& c != '&'
&& c != '|'
&& c != '!'
&& c != '('
&& c != ')' =>
{
let mut atom_expr = Expr::Atom(c);
if pending_not {
atom_expr = Expr::Not(Box::new(atom_expr));
pending_not = false;
}
if let Some(Expr::And(ref mut terms)) = current_expr {
terms.push(atom_expr);
} else if let Some(Expr::Or(ref mut terms)) = current_expr {
terms.push(atom_expr);
} else {
current_expr = Some(atom_expr);
}
}
'&' => {
if let Some(Expr::Or(_)) = current_expr {
let and_expression = Some(Expr::And(vec![current_expr.take().unwrap()]));
current_expr = and_expression
}
if let Some(Expr::And(_)) = current_expr {
// We do nothing here
} else if let Some(atom) = current_expr.take() {
current_expr = Some(Expr::And(vec![atom]));
} else {
return Err(ParseError::UnexpectedEnd);
}
}
'|' => {
if let Some(Expr::And(_)) = current_expr {
let or_expression = Some(Expr::Or(vec![current_expr.take().unwrap()]));
current_expr = or_expression
}
if let Some(Expr::Or(_)) = current_expr {
// We do nothing here
} else if let Some(atom) = current_expr.take() {
current_expr = Some(Expr::Or(vec![atom]));
} else {
return Err(ParseError::UnexpectedEnd);
}
}
'!' => {
pending_not = true;
}
'(' => {
let mut expr = self.recursive_parse(i + 1).unwrap();
if pending_not {
expr = Expr::Not(Box::new(expr));
pending_not = false;
}
if let Some(Expr::And(ref mut terms)) = current_expr {
terms.push(expr);
} else if let Some(Expr::Or(ref mut terms)) = current_expr {
terms.push(expr);
} else {
current_expr = Some(expr);
}
//Move to the `)`
let mut temp_index = i;
let mut bracket_counter = 1;
while bracket_counter > 0 {
temp_index += 1;
if self.input[temp_index] == '(' {
bracket_counter += 1;
}
if self.input[temp_index] == ')' {
bracket_counter -= 1;
}
}
i = temp_index;
}
')' => {
return Ok(current_expr.unwrap());
}
_ => return Err(ParseError::UnexpectedExpr),
}
i += 1
}
current_expr.ok_or(ParseError::UnexpectedEnd)
}
}
#[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(inner_expr) => Value::Expr(Expr::Not(Box::new(inner_expr))),
},
Expr::And(terms) => {
let mut new_terms = Vec::new();
for term in terms {
match eval(term, truthy, falsy) {
Value::False => return Value::False,
Value::True => continue,
Value::Expr(inner) => new_terms.push(inner),
}
}
if new_terms.is_empty() {
Value::True
} else if new_terms.len() == 1 {
Value::Expr(new_terms.pop().unwrap())
} else {
Value::Expr(Expr::And(new_terms))
}
}
Expr::Or(terms) => {
let mut new_terms = Vec::new();
for term in terms {
match eval(term, truthy, falsy) {
Value::True => return Value::True,
Value::False => continue,
Value::Expr(inner) => new_terms.push(inner),
}
}
if new_terms.is_empty() {
Value::False
} else if new_terms.len() == 1 {
Value::Expr(new_terms.pop().unwrap())
} else {
Value::Expr(Expr::Or(new_terms))
}
}
}
}

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

Compiling solution v0.1.0 (/tmp/d20241224-258381-360krq/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.81s
     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 ... 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_errors_basic ... ok
test solution_test::test_parser_error_unexpected_end ... FAILED
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_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_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_multiple_not stdout ----
thread '<unnamed>' panicked at 'called `Result::unwrap()` on an `Err` value: UnexpectedUnaryOp', tests/solution_test.rs:142:42
thread 'solution_test::test_parser_multiple_not' panicked at 'called `Result::unwrap()` on an `Err` value: UnexpectedUnaryOp', tests/solution_test.rs:140:5


failures:
    solution_test::test_error_paren_mismatched
    solution_test::test_parser_error_unexpected_end
    solution_test::test_parser_multiple_not

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

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

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

Александър качи първо решение на 21.12.2024 00:04 (преди 9 месеца)